Completed
Branch master (a15a51)
by Sam
01:56
created

PersistenceManager::hasUser()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 1
Metric Value
c 2
b 0
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 2
1
<?php
2
3
namespace Jalle19\StatusManager;
4
5
use Jalle19\StatusManager\Database;
6
use Jalle19\StatusManager\Database\Channel;
7
use Jalle19\StatusManager\Database\ChannelQuery;
8
use Jalle19\StatusManager\Database\Connection;
9
use Jalle19\StatusManager\Database\ConnectionQuery;
10
use Jalle19\StatusManager\Database\Input;
11
use Jalle19\StatusManager\Database\InputQuery;
12
use Jalle19\StatusManager\Database\InstanceQuery;
13
use Jalle19\StatusManager\Database\Subscription;
14
use Jalle19\StatusManager\Database\SubscriptionQuery;
15
use Jalle19\StatusManager\Database\User;
16
use Jalle19\StatusManager\Database\UserQuery;
17
use Jalle19\StatusManager\Subscription\StateChange;
18
use Jalle19\tvheadend\model\ConnectionStatus;
19
use Jalle19\tvheadend\model\InputStatus;
20
use Jalle19\tvheadend\model\SubscriptionStatus;
21
use Jalle19\tvheadend\Tvheadend;
22
use Psr\Log\LoggerInterface;
23
24
/**
25
 * Handles persisting of objects to the database
26
 *
27
 * @package   Jalle19\StatusManager
28
 * @copyright Copyright &copy; Sam Stenvall 2015-
29
 * @license   https://www.gnu.org/licenses/gpl.html The GNU General Public License v2.0
30
 */
31
class PersistenceManager
32
{
33
34
	/**
35
	 * @var LoggerInterface
36
	 */
37
	private $_logger;
38
39
40
	/**
41
	 * @param LoggerInterface $logger
42
	 */
43
	public function __construct(LoggerInterface $logger)
44
	{
45
		$this->_logger = $logger;
46
	}
47
48
49
	/**
50
	 * @param Tvheadend $instance
51
	 *
52
	 * @throws \Propel\Runtime\Exception\PropelException
53
	 */
54
	public function onInstanceSeen(Tvheadend $instance)
55
	{
56
		if ($this->hasInstance($instance))
57
			return;
58
59
		$instanceModel = new Database\Instance();
60
		$instanceModel->setPrimaryKey($instance->getHostname());
61
		$instanceModel->save();
62
63
		$this->_logger->info('Stored new instance {instanceName}', [
64
			'instanceName' => $instance->getHostname(),
65
		]);
66
67
		// Create a special user for eventual DVR subscriptions
68
		$user = new User();
69
		$user->setInstance($instanceModel);
70
		$user->setName(User::NAME_DVR);
71
		$user->save();
72
73
		$this->_logger->info('Stored new special user (instance: {instanceName}, user: {userName})', [
74
			'instanceName' => $instance->getHostname(),
75
			'userName'     => $user->getName(),
76
		]);
77
	}
78
79
80
	/**
81
	 * @param string           $instanceName
82
	 * @param ConnectionStatus $connectionStatus
83
	 */
84
	public function onConnectionSeen($instanceName, ConnectionStatus $connectionStatus)
85
	{
86
		if ($this->hasConnection($instanceName, $connectionStatus))
87
			return;
88
89
		$user = null;
90
91
		// Find the user object when applicable
92
		if (!$connectionStatus->isAnonymous())
93
		{
94
			$this->onUserSeen($instanceName, $connectionStatus->user);
95
96
			$user = UserQuery::create()->filterByInstanceName($instanceName)->filterByName($connectionStatus->user)
97
			                 ->findOne();
98
		}
99
100
		$connection = new Connection();
101
		$connection->setInstanceName($instanceName)->setPeer($connectionStatus->peer)
102
		           ->setUser($user)
103
		           ->setStarted($connectionStatus->started)->setType($connectionStatus->type)->save();
104
105
		$this->_logger->info('Stored new connection (instance: {instanceName}, peer: {peer})', [
106
			'instanceName' => $instanceName,
107
			'peer'         => $connectionStatus->peer,
108
		]);
109
	}
110
111
112
	/**
113
	 * @param string      $instanceName
114
	 * @param InputStatus $inputStatus
115
	 */
116
	public function onInputSeen($instanceName, InputStatus $inputStatus)
117
	{
118
		// Update the input and started fields for existing inputs
119
		if ($this->hasInput($inputStatus->uuid))
120
		{
121
			$input = InputQuery::create()->findPk($inputStatus->uuid);
122
			$input->setStarted(new \DateTime())->setWeight($inputStatus->weight);
123
124
			return;
125
		}
126
127
		$input = new Input();
128
		$input->setPrimaryKey($inputStatus->uuid);
129
		$input->setInstanceName($instanceName)
130
		      ->setStarted(new \DateTime())
131
		      ->setInput($inputStatus->input)
132
		      ->setWeight($inputStatus->weight)
133
		      ->setNetwork(Input::parseNetwork($inputStatus))
134
		      ->setMux(Input::parseMux($inputStatus))->save();
135
136
		$this->_logger->info('Stored new input (instance: {instanceName}, network: {network}, mux: {mux}, weight: {weight})',
137
			[
138
				'instanceName' => $instanceName,
139
				'network'      => $input->getNetwork(),
140
				'mux'          => $input->getMux(),
141
				'weight'       => $input->getWeight(),
142
			]);
143
	}
144
145
146
	/**
147
	 * @param string $instanceName
148
	 * @param string $userName
149
	 *
150
	 * @throws \Propel\Runtime\Exception\PropelException
151
	 */
152
	public function onUserSeen($instanceName, $userName)
153
	{
154
		if ($this->hasUser($instanceName, $userName))
155
			return;
156
157
		$user = new User();
158
		$user->setInstanceName($instanceName)->setName($userName);
159
		$user->save();
160
161
		$this->_logger->info('Stored new user (instance: {instanceName}, username: {userName})', [
162
			'instanceName' => $instanceName,
163
			'userName'     => $userName,
164
		]);
165
	}
166
167
168
	/**
169
	 * @param string $instanceName
170
	 * @param string $channelName
171
	 *
172
	 * @throws \Propel\Runtime\Exception\PropelException
173
	 */
174
	public function onChannelSeen($instanceName, $channelName)
175
	{
176
		if ($this->hasChannel($instanceName, $channelName))
177
			return;
178
179
		$channel = new Channel();
180
		$channel->setInstanceName($instanceName)->setName($channelName);
181
		$channel->save();
182
183
		$this->_logger->info('Stored new channel (instance: {instanceName}, name: {channelName})', [
184
			'instanceName' => $instanceName,
185
			'channelName'  => $channelName,
186
		]);
187
	}
188
189
190
	/**
191
	 * @param string             $instanceName
192
	 * @param SubscriptionStatus $status
193
	 *
194
	 * @throws \Propel\Runtime\Exception\PropelException
195
	 */
196
	public function onSubscriptionSeen($instanceName, SubscriptionStatus $status)
197
	{
198
		// Ignore EPG grabber subscriptions
199
		if ($status->getType() === SubscriptionStatus::TYPE_EPGGRAB)
200
			return;
201
202
		// Determine the username to store for the subscription
203
		$username = $status->username;
204
205
		switch ($status->getType())
206
		{
207
			case SubscriptionStatus::TYPE_RECORDING:
208
				$username = 'dvr';
209
				break;
210
		}
211
212
		// Get the instance, user and channel
213
		$instance = InstanceQuery::create()->findPk($instanceName);
214
		$user     = UserQuery::create()->filterByInstance($instance)->filterByName($username)->findOne();
215
216
		// Ensure the channel exists
217
		$this->onChannelSeen($instanceName, $status->channel);
218
		$channel = ChannelQuery::create()->filterByInstance($instance)->filterByName($status->channel)->findOne();
219
220
		if ($this->hasSubscription($instance, $user, $channel, $status))
221
			return;
222
223
		// Determine which input the subscription uses
224
		$input = InputQuery::create()->filterBySubscriptionStatus($instanceName, $status)->findOne();
225
226
		if ($input === null)
227
		{
228
			$this->_logger->warning('Got subscription that cannot be tied to an input ({instanceName}, user: {userName}, channel: {channelName})',
229
				[
230
					'instanceName' => $instanceName,
231
					'userName'     => $user !== null ? $user->getName() : 'N/A',
232
					'channelName'  => $channel->getName(),
233
				]);
234
235
			return;
236
		}
237
238
		$subscription = new Subscription();
239
		$subscription->setInstance($instance)->setInput($input)->setUser($user)->setChannel($channel)
240
		             ->setSubscriptionId($status->id)->setStarted($status->start)->setTitle($status->title)
241
		             ->setService($status->service);
242
		$subscription->save();
243
244
		$this->_logger->info('Stored new subscription (instance: {instanceName}, user: {userName}, channel: {channelName})',
245
			[
246
				'instanceName' => $instanceName,
247
				'userName'     => $user !== null ? $user->getName() : 'N/A',
248
				'channelName'  => $channel->getName(),
249
			]);
250
	}
251
252
253
	/**
254
	 * @param string      $instanceName
255
	 * @param StateChange $stateChange
256
	 */
257
	public function onSubscriptionStateChange($instanceName, StateChange $stateChange)
258
	{
259
		// We only need to persist subscription stops
260
		if ($stateChange->getState() === StateChange::STATE_SUBSCRIPTION_STARTED)
261
			return;
262
263
		// Find the latest matching subscription
264
		$subscription = SubscriptionQuery::create()->filterByInstanceName($instanceName)
265
		                                 ->filterBySubscriptionId($stateChange->getSubscriptionId())
266
		                                 ->addDescendingOrderByColumn('started')->findOne();
267
268
		// EPG grab subscriptions are not stored so we don't want to log these with a high level
269
		if ($subscription === null)
270
		{
271
			$this->_logger->debug('Got subscription stop without a matching start (instance: {instanceName}, subscription: {subscriptionId})',
272
				[
273
					'instanceName'   => $instanceName,
274
					'subscriptionId' => $stateChange->getSubscriptionId(),
275
				]);
276
277
			return;
278
		}
279
280
		$subscription->setStopped(new \DateTime());
281
		$subscription->save();
282
283
		$user    = $subscription->getUser();
284
		$channel = $subscription->getChannel();
285
286
		$this->_logger->info('Stored subscription stop (instance: {instanceName}, user: {userName}, channel: {channelName})',
287
			[
288
				'instanceName' => $instanceName,
289
				'userName'     => $user !== null ? $user->getName() : 'N/A',
290
				'channelName'  => $channel->getName(),
291
			]);
292
	}
293
294
295
	/**
296
	 * @param Tvheadend $instance
297
	 *
298
	 * @return bool whether the instance exists in the database
299
	 */
300
	private function hasInstance(Tvheadend $instance)
301
	{
302
		return InstanceQuery::create()->findPk($instance->getHostname()) !== null;
303
	}
304
305
306
	/**
307
	 * @param                  $instanceName
308
	 * @param ConnectionStatus $connectionStatus
309
	 *
310
	 * @return bool whether the connection exists in the database
311
	 */
312
	private function hasConnection($instanceName, ConnectionStatus $connectionStatus)
313
	{
314
		return ConnectionQuery::create()->filterByInstanceName($instanceName)->filterByPeer($connectionStatus->peer)
315
		                      ->filterByStarted($connectionStatus->started)->findOne() !== null;
316
	}
317
318
319
	/**
320
	 * @param string $uuid
321
	 *
322
	 * @return bool
323
	 */
324
	private function hasInput($uuid)
325
	{
326
		return InputQuery::create()->findPk($uuid) !== null;
327
	}
328
329
330
	/**
331
	 * @param string $instanceName
332
	 * @param string $userName
333
	 *
334
	 * @return bool
335
	 */
336
	private function hasUser($instanceName, $userName)
337
	{
338
		return UserQuery::create()->filterByInstanceName($instanceName)->filterByName($userName)->findOne() !== null;
339
	}
340
341
342
	/**
343
	 * @param string $instanceName
344
	 * @param string $channelName
345
	 *
346
	 * @return bool
347
	 */
348
	private function hasChannel($instanceName, $channelName)
349
	{
350
		return ChannelQuery::create()->filterByInstanceName($instanceName)->filterByName($channelName)
351
		                   ->findOne() !== null;
352
	}
353
354
355
	/**
356
	 * @param Database\Instance  $instance
357
	 * @param User|null          $user
358
	 * @param Channel            $channel
359
	 * @param SubscriptionStatus $subscription
360
	 *
361
	 * @return bool
362
	 * @throws \Propel\Runtime\Exception\PropelException
363
	 */
364
	private function hasSubscription(
365
		Database\Instance $instance,
366
		$user,
367
		Channel $channel,
368
		SubscriptionStatus $subscription
369
	) {
370
		// Not all subscriptions are tied to a user
371
		$userId = $user !== null ? $user->getId() : null;
372
373
		return SubscriptionQuery::create()->filterByInstance($instance)->filterByUserId($userId)
374
		                        ->filterByChannel($channel)
375
		                        ->filterBySubscriptionId($subscription->id)->filterByStarted($subscription->start)
376
		                        ->findOne() !== null;
377
	}
378
379
}
380