Completed
Push — feature/servers-redesign ( 78b660...b795b9 )
by Vladimir
03:34
created

Server::getMatchCount()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 13
Code Lines 8

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 13
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 8
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
     * The server's status
73
     * @var string
74
     */
75
    protected $status;
76
77
    /**
78
     * The name of the database table used for queries
79
     */
80
    const TABLE = "servers";
81
82
    const CREATE_PERMISSION = Permission::ADD_SERVER;
83
    const EDIT_PERMISSION = Permission::EDIT_SERVER;
84
    const SOFT_DELETE_PERMISSION = Permission::SOFT_DELETE_SERVER;
85
    const HARD_DELETE_PERMISSION = Permission::HARD_DELETE_SERVER;
86
87
    /**
88
     * {@inheritdoc}
89
     */
90
    protected function assignResult($server)
91
    {
92
        $this->name = $server['name'];
93
        $this->domain = $server['domain'];
94
        $this->port = $server['port'];
95
        $this->country = $server['country'];
96
        $this->owner = $server['owner'];
97
        $this->online = $server['online'];
98
        $this->info = unserialize($server['info']);
99
        $this->api_key = ApiKey::get($server['api_key']);
100
        $this->updated = TimeDate::fromMysql($server['updated']);
101
        $this->status = $server['status'];
102
    }
103
104
    /**
105
     * Add a new server
106
     *
107
     * @param string $name    The name of the server
108
     * @param string $domain  The domain of the server (e.g. server.com)
109
     * @param string $port    The port of the server (e.g. 5154)
110
     * @param int    $country The ID of the country
111
     * @param int    $owner   The ID of the server owner
112
     *
113
     * @return Server An object that represents the sent message
114
     */
115
    public static function addServer($name, $domain, $port, $country, $owner)
116
    {
117
        $key = ApiKey::getKeyByOwner($owner);
118
119
        $server = self::create(array(
120
            'name'    => $name,
121
            'domain'  => $domain,
122
            'port'    => $port,
123
            'country' => $country,
124
            'owner'   => $owner,
125
            'api_key' => $key->getId(),
126
            'status'  => 'active',
127
        ), 'updated');
128
        $server->forceUpdate();
129
130
        return $server;
131
    }
132
133
    /**
134
     * Update the server with current bzfquery information
135
     * return self
136
     */
137
    public function forceUpdate()
138
    {
139
        $this->info = bzfquery($this->getAddress());
140
        $this->updated = TimeDate::now();
141
        $this->online = !isset($this->info['error']);
142
143
        $this->db->execute(
144
        "UPDATE servers SET info = ?, online = ?, updated = UTC_TIMESTAMP() WHERE id = ?",
145
        array(serialize($this->info), $this->online, $this->id)
146
    );
147
148
    // If a server is offline, log it
149
        if (!$this->online) {
150
            if ($logger = \Service::getContainer()->get('logger')) {
151
                $id = $this->getId();
152
                $address = $this->getAddress();
153
                $reason = $this->info['error'];
154
155
                $logger->notice("Connection to server #$id ($address) failed: $reason");
156
            }
157
        }
158
159
        return $this;
160
    }
161
162
    /**
163
     * Checks if the server is online (listed on the public list server)
164
     * @return bool Whether the server is online
165
     */
166
    public function isOnline()
167
    {
168
        return $this->online;
169
    }
170
171
    /**
172
     * Checks if the server has players
173
     * @return bool Whether the server has any players
174
     */
175
    public function hasPlayers()
176
    {
177
        return $this->info['numPlayers'] > 0;
178
    }
179
180
    /**
181
     * Gets the number of players on the server
182
     * @return int The number of players
183
     */
184
    public function numPlayers()
185
    {
186
        return (isset($this->info['numPlayers'])) ? $this->info['numPlayers'] : 0;
187
    }
188
189
    /**
190
     * Gets the players on the server
191
     * @return array The players on the server
192
     */
193
    public function getPlayers()
194
    {
195
        if (isset($this->info['player'])) {
196
            return $this->info['player'];
197
        }
198
199
        return array();
200
    }
201
202
    /**
203
     * Checks if the last update is older than or equal to the update interval
204
     * @return bool Whether the information is older than the update interval
205
     */
206
    public function staleInfo()
207
    {
208
        $update_time = $this->updated->copy();
209
        $update_time->modify(Service::getParameter('bzion.miscellaneous.update_interval'));
210
211
        return TimeDate::now() >= $update_time;
212
    }
213
214
    /**
215
     * The ApiKey assigned to this server
216
     *
217
     * @return \CachedModel|int|null|static
218
     */
219
    public function getApiKey()
220
    {
221
        return $this->api_key;
222
    }
223
224
    /**
225
     * Gets the server's ip address
226
     * @return string The server's ip address
227
     */
228
    public function getServerIp()
229
    {
230
        return $this->info['ip'];
231
    }
232
233
    /**
234
     * Get the server's name
235
     * @return string
236
     */
237
    public function getName()
238
    {
239
        return $this->name;
240
    }
241
242
    /**
243
     * Get the domain of the server
244
     *
245
     * @return string The server's domain
246
     */
247
    public function getDomain()
248
    {
249
        return $this->domain;
250
    }
251
252
    /**
253
     * Get the port of the server
254
     *
255
     * @return int The port number
256
     */
257
    public function getPort()
258
    {
259
        return $this->port;
260
    }
261
262
    /**
263
     * Get the server's IP address or hostname
264
     * @return string
265
     */
266
    public function getAddress()
267
    {
268
        return $this->domain . ":" . $this->port;
269
    }
270
271
    /**
272
     * Get when the server information was last updated
273
     * @return TimeDate
274
     */
275
    public function getUpdated()
276
    {
277
        return $this->updated->copy();
278
    }
279
280
    /**
281
     * Get the country the server is in
282
     * @return Country The country the server is located in
283
     */
284
    public function getCountry()
285
    {
286
        return Country::get($this->country);
287
    }
288
289
    /**
290
     * Get the owner of the server
291
     * @return Player
292
     */
293
    public function getOwner()
294
    {
295
        return Player::get($this->owner);
296
    }
297
298
    /**
299
     * Get the number of matches that have occurred on this server
300
     *
301
     * @return int
302
     */
303
    public function getMatchCount()
304
    {
305
        $qb = new MatchQueryBuilder('Match', [
306
            'columns' => [
307
                'server' => 'server_id'
308
            ]
309
        ]);
310
        $query = $qb
311
            ->where('server')->equals($this->getId())
312
            ->count();
313
314
        return $query;
315
    }
316
317
    /**
318
     * Returns the amount of time passed since the server was last updated
319
     * @return TimeDate
320
     */
321
    public function getLastUpdate()
322
    {
323
        return $this->updated;
324
    }
325
326
    /**
327
     * Set the name of the server
328
     *
329
     * @param string $name The new name of the server
330
     *
331
     * @return self
332
     */
333
    public function setName($name)
334
    {
335
        return $this->updateProperty($this->name, 'name', $name);
336
    }
337
338
    /**
339
     * Set the address of the server
340
     *
341
     * @param string $address The new address of the server
342
     *
343
     * @deprecated Use setDomain() and setPort() instead
344
     *
345
     * @return self
346
     */
347
    public function setAddress($address)
348
    {
349
        list($domain, $port) = explode(":", $address);
350
351
        $this->setDomain($domain);
352
        $this->setPort($port);
353
354
        return $this;
355
    }
356
357
    /**
358
     * Set the domain of the server
359
     *
360
     * @param $domain string The new domain of the server
361
     *
362
     * @return self
363
     */
364
    public function setDomain($domain)
365
    {
366
        return $this->updateProperty($this->domain, 'domain', $domain);
367
    }
368
369
    /**
370
     * Set the port of the server
371
     *
372
     * @param $port int The new port of the server
373
     *
374
     * @return self
375
     */
376
    public function setPort($port)
377
    {
378
        return $this->updateProperty($this->port, 'port', $port);
379
    }
380
381
    /**
382
     * Set the id of the owner of the server
383
     *
384
     * @param int $ownerId The ID of the new owner of the server
385
     *
386
     * @return self
387
     */
388
    public function setOwner($ownerId)
389
    {
390
        return $this->updateProperty($this->owner, 'owner', $ownerId);
391
    }
392
393
    /**
394
     * Set the id of the country of the server
395
     *
396
     * @param int $countryId The ID of the new country of the server
397
     *
398
     * @return self
399
     */
400
    public function setCountry($countryId)
401
    {
402
        return $this->updateProperty($this->country, 'country', $countryId);
403
    }
404
405
    /**
406
     * Get all the servers in the database that have an active status
407
     * @return Server[] An array of server objects
408
     */
409
    public static function getServers()
410
    {
411
        return self::arrayIdToModel(self::fetchIdsFrom("status", array("active"), false, "ORDER BY name"));
412
    }
413
414
    /**
415
     * Get a query builder for servers
416
     * @return QueryBuilder
417
     */
418 View Code Duplication
    public static function getQueryBuilder()
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...
419
    {
420
        return new QueryBuilder('Server', array(
421
            'columns' => array(
422
                'name'   => 'name',
423
                'domain' => 'domain',
424
                'port'   => 'port',
425
                'status' => 'status',
426
            ),
427
            'name' => 'name'
428
        ));
429
    }
430
431
    /**
432
     * Get the Server model with the respective address
433
     *
434
     * @param  string $address The address in the format of `domain:port`
435
     *
436
     * @return static
437
     */
438
    public static function fetchFromAddress($address)
439
    {
440
        if (strpos($address, ':') === false) {
441
            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...
442
        }
443
444
        list($domain, $port) = explode(':', $address);
445
446
        $qb = self::getQueryBuilder();
447
        $query = $qb
448
            ->where('domain')->equals($domain)
449
            ->where('port')->equals($port)
450
            ->active()
451
            ->getModels($fast = true)
452
        ;
453
454
        if (count($query) > 0) {
455
            return $query[0];
456
        }
457
458
        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...
459
    }
460
}
461