Completed
Push — feature/pixie-port ( a7bad2...84efcb )
by Vladimir
03:38
created

Server::isOfficialServer()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 4
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 0
1
<?php
0 ignored issues
show
Coding Style Compatibility introduced by
For compatibility and reusability of your code, PSR1 recommends that a file should introduce either new symbols (like classes, functions, etc.) or have side-effects (like outputting something, or including other files), but not both at the same time. The first symbol is defined on line 15 and the first side effect is on line 9.

The PSR-1: Basic Coding Standard recommends that a file should either introduce new symbols, that is classes, functions, constants or similar, or have side effects. Side effects are anything that executes logic, like for example printing output, changing ini settings or writing to a file.

The idea behind this recommendation is that merely auto-loading a class should not change the state of an application. It also promotes a cleaner style of programming and makes your code less prone to errors, because the logic is not spread out all over the place.

To learn more about the PSR-1, please see the PHP-FIG site on the PSR-1.

Loading history...
2
/**
3
 * This file contains functionality relating to the official BZFlag match servers for the league
4
 *
5
 * @package    BZiON\Models
6
 * @license    https://github.com/allejo/bzion/blob/master/LICENSE.md GNU General Public License Version 3
7
 */
8
9
include_once DOC_ROOT . "/includes/bzfquery.php";
10
11
/**
12
 * A BZFlag server
13
 * @package    BZiON\Models
14
 */
15
class Server extends UrlModel implements NamedModel
16
{
17
    /**
18
     * The name of the server
19
     * @var string
20
     */
21
    protected $name;
22
23
    /**
24
     * The domain of the server
25
     * @var string
26
     */
27
    protected $domain;
28
29
    /**
30
     * The port of the server
31
     * @var int
32
     */
33
    protected $port;
34
35
    /**
36
     * The id of the country the server is located in
37
     * @var int
38
     */
39
    protected $country;
40
41
    /**
42
     * The id of the owner of the server
43
     * @var int
44
     */
45
    protected $owner;
46
47
    /**
48
     * Whether the server is listed on the public list server
49
     * @var bool
50
     */
51
    protected $online;
52
53
    /**
54
     * The server's bzfquery information
55
     * @var array
56
     */
57
    protected $info;
58
59
    /**
60
     * The ID of the API key assigned to this server
61
     * @var ApiKey
62
     */
63
    protected $api_key;
64
65
    /**
66
     * The date of the last bzfquery of the server
67
     * @var TimeDate
68
     */
69
    protected $updated;
70
71
    /**
72
     * Whether or not this server is capable of hosting official matches.
73
     *
74
     * @var bool
75
     */
76
    protected $is_official_server;
77
78
    /**
79
     * Whether or not this server is dedicated to being a replay server.
80
     *
81
     * @var bool
82
     */
83
    protected $is_replay_server;
84
85
    /**
86
     * Whether or not this server has been marked as "inactive" and is only kept for historical purposes.
87
     *
88
     * @var bool
89
     */
90
    protected $is_inactive;
91
92
    const DELETED_COLUMN = 'is_deleted';
93
    const TABLE = "servers";
94
95
    const CREATE_PERMISSION = Permission::ADD_SERVER;
96
    const EDIT_PERMISSION = Permission::EDIT_SERVER;
97
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_SERVER;
98
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_SERVER;
99
100
    /**
101
     * {@inheritdoc}
102
     */
103
    protected function assignResult($server)
104
    {
105
        $this->name = $server['name'];
106
        $this->domain = $server['domain'];
107
        $this->port = $server['port'];
108
        $this->country = $server['country'];
109
        $this->owner = $server['owner'];
110
        $this->online = $server['online'];
111
        $this->info = unserialize($server['info']);
112
        $this->api_key = ApiKey::get($server['api_key']);
113
        $this->updated = TimeDate::fromMysql($server['updated']);
114
        $this->is_official_server = $server['is_official_server'];
115
        $this->is_replay_server = $server['is_replay_server'];
116
        $this->is_inactive = $server['is_inactive'];
117
    }
118
119
    /**
120
     * Update the server with current bzfquery information
121
     * return self
122
     */
123
    public function forceUpdate()
124
    {
125
        $this->info = bzfquery($this->getAddress());
126
        $this->updated = TimeDate::now();
127
        $this->online = !isset($this->info['error']);
128
129
        $this->db->execute(
130
        "UPDATE servers SET info = ?, online = ?, updated = UTC_TIMESTAMP() WHERE id = ?",
131
        array(serialize($this->info), $this->online, $this->id)
132
    );
133
134
    // If a server is offline, log it
135
        if (!$this->online) {
136
            if ($logger = \Service::getContainer()->get('logger')) {
137
                $id = $this->getId();
138
                $address = $this->getAddress();
139
                $reason = $this->info['error'];
140
141
                $logger->notice("Connection to server #$id ($address) failed: $reason");
142
            }
143
        }
144
145
        return $this;
146
    }
147
148
    /**
149
     * Checks if the server is online (listed on the public list server)
150
     * @return bool Whether the server is online
151
     */
152
    public function isOnline()
153
    {
154
        return $this->online;
155
    }
156
157
    /**
158
     * Checks if the server has players
159
     * @return bool Whether the server has any players
160
     */
161
    public function hasPlayers()
162
    {
163
        return $this->info['numPlayers'] > 0;
164
    }
165
166
    /**
167
     * Gets the number of players on the server
168
     * @return int The number of players
169
     */
170
    public function numPlayers()
171
    {
172
        return (isset($this->info['numPlayers'])) ? $this->info['numPlayers'] : 0;
173
    }
174
175
    /**
176
     * Gets the players on the server
177
     * @return array The players on the server
178
     */
179
    public function getPlayers()
180
    {
181
        if (isset($this->info['player'])) {
182
            return $this->info['player'];
183
        }
184
185
        return array();
186
    }
187
188
    /**
189
     * Checks if the last update is older than or equal to the update interval
190
     * @return bool Whether the information is older than the update interval
191
     */
192
    public function staleInfo()
193
    {
194
        $update_time = $this->updated->copy();
195
        $update_time->modify(Service::getParameter('bzion.miscellaneous.update_interval'));
196
197
        return TimeDate::now() >= $update_time;
198
    }
199
200
    /**
201
     * The ApiKey assigned to this server
202
     *
203
     * @return \CachedModel|int|null|static
204
     */
205
    public function getApiKey()
206
    {
207
        return $this->api_key;
208
    }
209
210
    /**
211
     * Gets the server's ip address
212
     * @return string The server's ip address
213
     */
214
    public function getServerIp()
215
    {
216
        return $this->info['ip'];
217
    }
218
219
    /**
220
     * Get the server's name
221
     * @return string
222
     */
223
    public function getName()
224
    {
225
        return $this->name;
226
    }
227
228
    /**
229
     * Get the domain of the server
230
     *
231
     * @return string The server's domain
232
     */
233
    public function getDomain()
234
    {
235
        return $this->domain;
236
    }
237
238
    /**
239
     * Get the port of the server
240
     *
241
     * @return int The port number
242
     */
243
    public function getPort()
244
    {
245
        return $this->port;
246
    }
247
248
    /**
249
     * Get the server's IP address or hostname
250
     * @return string
251
     */
252
    public function getAddress()
253
    {
254
        return $this->domain . ":" . $this->port;
255
    }
256
257
    /**
258
     * Get when the server information was last updated
259
     * @return TimeDate
260
     */
261
    public function getUpdated()
262
    {
263
        return $this->updated->copy();
264
    }
265
266
    /**
267
     * Get the country the server is in
268
     * @return Country The country the server is located in
269
     */
270
    public function getCountry()
271
    {
272
        return Country::get($this->country);
273
    }
274
275
    /**
276
     * Get the owner of the server
277
     * @return Player
278
     */
279
    public function getOwner()
280
    {
281
        return Player::get($this->owner);
282
    }
283
284
    /**
285
     * Get the number of matches that have occurred on this server
286
     *
287
     * @return int
288
     */
289
    public function getMatchCount()
290
    {
291
        $qb = new MatchQueryBuilder('Match', [
292
            'columns' => [
293
                'server' => 'server_id'
294
            ]
295
        ]);
296
        $query = $qb
297
            ->where('server')->equals($this->getId())
298
            ->active()
299
            ->count()
300
        ;
301
302
        return $query;
303
    }
304
305
    /**
306
     * Returns the amount of time passed since the server was last updated
307
     * @return TimeDate
308
     */
309
    public function getLastUpdate()
310
    {
311
        return $this->updated;
312
    }
313
314
    /**
315
     * Get whether or not this server is only kept for historical purposes.
316
     *
317
     * The server is now "retired" or no longer used but is **not** soft deleted.
318
     *
319
     * @return bool
320
     */
321
    public function isInactive()
322
    {
323
        return (bool)$this->is_inactive;
324
    }
325
326
    /**
327
     * Get whether or not this server is capable of hosting official matches
328
     *
329
     * @return bool
330
     */
331
    public function isOfficialServer()
332
    {
333
        return (bool)$this->is_official_server;
334
    }
335
336
    /**
337
     * Get whether or not this server is dedicated to serving replays.
338
     *
339
     * @return bool
340
     */
341
    public function isReplayServer()
342
    {
343
        return (bool)$this->is_replay_server;
344
    }
345
346
    /**
347
     * Set the name of the server
348
     *
349
     * @param string $name The new name of the server
350
     *
351
     * @return self
352
     */
353
    public function setName($name)
354
    {
355
        return $this->updateProperty($this->name, 'name', $name);
356
    }
357
358
    /**
359
     * Set the address of the server
360
     *
361
     * @param string $address The new address of the server
362
     *
363
     * @deprecated Use setDomain() and setPort() instead
364
     *
365
     * @return self
366
     */
367
    public function setAddress($address)
368
    {
369
        list($domain, $port) = explode(":", $address);
370
371
        $this->setDomain($domain);
372
        $this->setPort($port);
373
374
        return $this;
375
    }
376
377
    /**
378
     * Set the domain of the server
379
     *
380
     * @param $domain string The new domain of the server
381
     *
382
     * @return self
383
     */
384
    public function setDomain($domain)
385
    {
386
        return $this->updateProperty($this->domain, 'domain', $domain);
387
    }
388
389
    /**
390
     * Set the port of the server
391
     *
392
     * @param $port int The new port of the server
393
     *
394
     * @return self
395
     */
396
    public function setPort($port)
397
    {
398
        return $this->updateProperty($this->port, 'port', $port);
399
    }
400
401
    /**
402
     * Set the id of the owner of the server
403
     *
404
     * @param int $ownerId The ID of the new owner of the server
405
     *
406
     * @return self
407
     */
408
    public function setOwner($ownerId)
409
    {
410
        return $this->updateProperty($this->owner, 'owner', $ownerId);
411
    }
412
413
    /**
414
     * Set the id of the country of the server
415
     *
416
     * @param int $countryId The ID of the new country of the server
417
     *
418
     * @return self
419
     */
420
    public function setCountry($countryId)
421
    {
422
        return $this->updateProperty($this->country, 'country', $countryId);
423
    }
424
425
    /**
426
     * Set this server's inactivity status.
427
     *
428
     * @param bool $inactive
429
     *
430
     * @return static
431
     */
432
    public function setInactive($inactive)
433
    {
434
        return $this->updateProperty($this->is_inactive, 'is_inactive', $inactive);
435
    }
436
437
    /**
438
     * Set the official match capabilities of this server.
439
     *
440
     * @param bool $matchServer
441
     *
442
     * @return static
443
     */
444
    public function setOfficialServer($matchServer)
445
    {
446
        return $this->updateProperty($this->is_official_server, 'is_official_server', $matchServer);
447
    }
448
449
    /**
450
     * Set the replay status of this server.
451
     *
452
     * @param bool $replayServer
453
     *
454
     * @return static
455
     */
456
    public function setReplayServer($replayServer)
457
    {
458
        return $this->updateProperty($this->is_replay_server, 'is_replay_server', $replayServer);
459
    }
460
461
    /**
462
     * Add a new server
463
     *
464
     * @param string $name      The name of the server
465
     * @param string $domain    The domain of the server (e.g. server.com)
466
     * @param string $port      The port of the server (e.g. 5154)
467
     * @param int    $countryID The ID of the country
468
     * @param int    $ownerID   The ID of the server owner
469
     *
470
     * @return Server An object that represents the sent message
471
     */
472
    public static function addServer($name, $domain, $port, $countryID, $ownerID)
473
    {
474
        $key = ApiKey::getKeyByOwner($ownerID);
475
476
        $server = self::create([
477
            'name'    => $name,
478
            'domain'  => $domain,
479
            'port'    => $port,
480
            'country' => $countryID,
481
            'owner'   => $ownerID,
482
            'api_key' => $key->getId(),
483
        ], 'updated');
484
        $server->forceUpdate();
485
486
        return $server;
487
    }
488
489
    /**
490
     * Get a query builder for servers
491
     *
492
     * @throws Exception
493
     *
494
     * @return QueryBuilderFlex
495
     */
496
    public static function getQueryBuilder()
497
    {
498
        return QueryBuilderFlex::createForModel(Server::class)
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
499
            ->setNameColumn('name')
500
        ;
501
    }
502
503
    /**
504
     * {@inheritdoc}
505
     */
506 View Code Duplication
    public static function getActiveModels(QueryBuilderFlex &$qb)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
507
    {
508
        $qb
509
            ->whereNot(self::DELETED_COLUMN, '=', self::DELETED_VALUE)
510
            ->whereNot('is_inactive', '=', true)
511
        ;
512
513
        return true;
514
    }
515
516
    /**
517
     * Get the Server model with the respective address
518
     *
519
     * @param  string $address The address in the format of `domain:port`
520
     *
521
     * @throws \Pixie\Exception
522
     * @throws Exception
523
     *
524
     * @return static
525
     */
526
    public static function fetchFromAddress($address)
527
    {
528
        if (strpos($address, ':') === false) {
529
            return Server::get(0);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
530
        }
531
532
        list($domain, $port) = explode(':', $address);
533
534
        $results = self::getQueryBuilder()
535
            ->where('domain', '=', $domain)
536
            ->where('port', '=', $port)
537
            ->active()
538
            ->getModels(true)
539
        ;
540
541
        if (count($results) > 0) {
542
            return $results[0];
543
        }
544
545
        return Server::get(0);
0 ignored issues
show
Coding Style introduced by
As per coding style, self should be used for accessing local static members.

This check looks for accesses to local static members using the fully qualified name instead of self::.

<?php

class Certificate {
    const TRIPLEDES_CBC = 'ASDFGHJKL';

    private $key;

    public function __construct()
    {
        $this->key = Certificate::TRIPLEDES_CBC;
    }
}

While this is perfectly valid, the fully qualified name of Certificate::TRIPLEDES_CBC could just as well be replaced by self::TRIPLEDES_CBC. Referencing local members with self:: assured the access will still work when the class is renamed, makes it perfectly clear that the member is in fact local and will usually be shorter.

Loading history...
546
    }
547
}
548