Completed
Push — work-fleets ( 8b8b7f...487af6 )
by SuperNova.WS
04:56
created

UnitList::unitsPropertySumById()   A

Complexity

Conditions 4
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 10
rs 9.2
cc 4
eloc 6
nc 3
nop 2
1
<?php
2
3
/**
4
 * Class UnitList
5
 * Indexed by DB_ID - as it should be!
6
 *
7
 *
8
 *
9
 * Hints for IDE - inherited from ArrayAccessV2
10
 *
11
 * @method Unit offsetGet($offset)
12
 * @property Unit[] $_container
13
 *
14
 */
15
class UnitList extends ArrayAccessV2 implements IDbRow, ILocation {
16
17
18
  // Properties ********************************************************************************************************
19
20
  // ILocation implementation ==========================================================================================
21
22
  /**
23
   * Type of this location
24
   *
25
   * @var int $locationType
26
   */
27
  protected static $locationType = LOC_UNIT_LIST;
28
  /**
29
   * @var ILocation $locatedAt
30
   */
31
  protected $locatedAt = null;
32
33
34
  // New properties ====================================================================================================
35
36
  /**
37
   * @var Unit[] $mapUnitIdToDb
38
   */
39
  // Нужно для корректного сохранения новых юнитов. Их db_id = 0, поэтому при добавлении в контейнер они будут перезаписывать друг друга
40
  // Соответственно - при сохраненнии флота надо проходить dbSave именно по $mapUnitIdToDb
41
  protected $mapUnitIdToDb = array();
42
43
44
  // Methods ***********************************************************************************************************
45
46
  // ILocation implementation ==========================================================================================
47
48
  public function getPlayerOwnerId() {
49
    return is_object($this->locatedAt) ? $this->locatedAt->getPlayerOwnerId() : null;
50
  }
51
52
  public function getLocationType() {
53
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationType() : LOC_NONE;
54
  }
55
56
  public function getLocationDbId() {
57
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationDbId() : null;
58
  }
59
60
  // TODO - достаточно установить один раз Unit::LocatedAt на UnitList, что бы затем все юниты автоматически брали наиболее актуальный locatedAt
61
  public function setLocatedAt($location) {
62
    $this->locatedAt = $location;
63
    // TODO - по факту не нужно - достточно один раз поставить на $this
64
//    foreach($this->_container as $unit) {
65
//      $unit->setLocatedAt($this->locatedAt);
66
//    }
67
  }
68
69
  public function getLocatedAt() {
70
    return $this->locatedAt;
71
  }
72
73
  public function getLocatedAtType() {
74
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationType() : LOC_NONE;
75
  }
76
77
  public function getLocatedAtDbId() {
78
    return is_object($this->locatedAt) ? $this->locatedAt->getLocationDbId() : 0;
79
  }
80
81
82
  // ArrayAccessV2 inheritance =========================================================================================
83
84
  /**
85
   * Adds link to unit object also to mapUnitIdToDb
86
   *
87
   * @param mixed $offset
88
   * @param Unit  $value
89
   */
90
  public function offsetSet($offset, $value) {
91
    if(isset($this->mapUnitIdToDb[$value->unitId])) {
92
      classSupernova::$debug->error('UnitList::offsetSet: Unit with UnitId ' . $value->unitId . ' already exists');
93
    }
94
    $this->mapUnitIdToDb[$value->unitId] = $value;
95
    parent::offsetSet($offset, $value);
96
  }
97
98
  public function offsetUnset($offset) {
99
    if(!empty($this[$offset]->unitId)) {
100
//      $unit_id = $this[$offset]->unitId;
0 ignored issues
show
Unused Code Comprehensibility introduced by
63% 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...
101
//      $this->mapUnitIdToDb[$unit_id] = null;
102
//      unset($this->mapUnitIdToDb[$unit_id]);
103
      unset($this->mapUnitIdToDb[$this[$offset]->unitId]);
104
    }
105
    parent::offsetUnset($offset);
106
  }
107
108
109
  // IDbRow implementation =============================================================================================
110
111
  /**
112
   * Loading object from DB by primary ID
113
   * Real location should be set before calling this method
114
   *
115
   * @param int $dbId - dbId is generally unused here. However it works as flag: 0 - just reset; (negative) - just reset; (positive) - proceed with loading
116
   */
117
  // TODO: Implement dbLoad() method.
118
  public function dbLoad($dbId) {
119
//    $this->_reset();
0 ignored issues
show
Unused Code Comprehensibility introduced by
72% 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...
120
121
    if($dbId <= 0) {
122
      return;
123
    }
124
125
    if(!is_object($this->locatedAt)) {
126
      classSupernova::$debug->error('UnitList::dbLoad have no locatedAt field set');
127
    }
128
129
    $unit_array = classSupernova::db_get_unit_list_by_location(0, $this->getLocationType(), $this->getLocationDbId());
130
    if(!is_array($unit_array)) {
131
      return;
132
    }
133
134
    foreach($unit_array as $unit_db_row) {
135
      $unit = $this->_createElement();
136
      $unit->setLocatedAt($this);
137
      $unit->dbRowParse($unit_db_row);
138
139
      // TODO - сюда вставить разборку бонусов данного юнитлиста - тех бонусов, которые Grants данный юнит добавить в список бонусов юнит-листа
140
141
      $this[$unit->dbId] = $unit;
142
    }
143
144
    // TODO - Применить бонусы от location
145
    // Точнее - опустить бонусы с юнитлиста (те, которые Grants) на каждый юнит (те, которые receives)
146
    // Вообще-то Receives это будут параметры каждого юнита
147
  }
148
149
  public function dbSave() {
150
    if(!is_object($this->locatedAt)) {
151
      classSupernova::$debug->error('UnitList::dbSave have no locatedAt field set');
152
    }
153
154
    foreach($this->mapUnitIdToDb as $unit) {
155
      $unit_db_id = $unit->dbId;
156
      $unit->dbSave();
157
158
      if($unit->isEmpty()) {
159
        // Removing unit object
160
        // TODO - change when there will be common bus for all objects
161
        // ...or should I? If COUNT is empty - it means that object does not exists in DB. So it should be deleted from PHP memory and cache too
162
        unset($this[$unit_db_id]);
163
      } else {
164
        if($unit->dbId <= 0) {
165
          classSupernova::$debug->error('Error writing unit to DB');
166
        }
167
        // If unit is new then putting unit object to container
168
        if(empty($this->_container[$unit->dbId])) {
169
          $this->_container[$unit->dbId] = $unit;
170
        }
171
      }
172
    }
173
  }
174
175
176
177
178
179
  // Other =============================================================================================================
180
181
  /**
182
   * @return Unit
183
   *
184
   * @version 41a6.31
185
   */
186
  // TODO - Factory
187
  public function _createElement() {
188
    return new Unit();
0 ignored issues
show
Bug Best Practice introduced by
The return type of return new \Unit(); (Unit) is incompatible with the return type of the parent method ArrayAccessV2::_createElement of type stdClass.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

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

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
189
  }
190
191
  /**
192
   * Set unit count of $unit_id to $unit_count
193
   * If there is no $unit_id - it will be created and saved to DB on dbSave
194
   *
195
   * @param int $unit_id
196
   * @param int $unit_count
197
   */
198
  public function unitSetCount($unit_id, $unit_count = 0) {
199
    $this->unitAdjustCount($unit_id, $unit_count, true);
200
  }
201
202
  public function unitGetCount($unit_id) {
203
    if(empty($this->mapUnitIdToDb[$unit_id])) {
204
      throw new Exception('Unit [' . $unit_id . '] is not exists in UnitList');
205
    }
206
    return $this->mapUnitIdToDb[$unit_id]->count;
207
  }
208
209
  /**
210
   * Adjust unit count of $unit_id by $unit_count - or just replace value
211
   * If there is no $unit_id - it will be created and saved to DB on dbSave
212
   *
213
   * @param int  $unit_id
214
   * @param int  $unit_count
215
   * @param bool $replace_value
216
   */
217
  public function unitAdjustCount($unit_id, $unit_count = 0, $replace_value = false) {
218
    if(empty($this->mapUnitIdToDb[$unit_id])) {
219
      // If unit not exists - creating one and setting all attributes
220
      $this->mapUnitIdToDb[$unit_id] = $this->_createElement();
221
      $this->mapUnitIdToDb[$unit_id]->setUnitId($unit_id);
222
      $this->mapUnitIdToDb[$unit_id]->setLocatedAt($this);
223
    }
224
225
    if($replace_value) {
226
      $this->mapUnitIdToDb[$unit_id]->count = $unit_count;
227
    } else {
228
      $this->mapUnitIdToDb[$unit_id]->adjustCount($unit_count);
229
    }
230
  }
231
232
  /**
233
   * Get unit list in array as $unit_id => $unit_count
234
   *
235
   * @return array
236
   */
237
  public function unitsGetArray() {
238
    $result = array();
239
    foreach($this->mapUnitIdToDb as $unit) {
240
      $result[$unit->unitId] = $unit->count;
241
    }
242
243
    return $result;
244
  }
245
246
  public function unitsCountApplyLossMultiplier($ships_lost_multiplier) {
247
    foreach($this->mapUnitIdToDb as $unit_id => $unit) {
248
      $unit->count = floor($unit->count * $ships_lost_multiplier);
249
    }
250
  }
251
252
  public function unitsCount() {
253
    return $this->unitsPropertySumById(0, 'count');
254
  }
255
256
  public function unitsCapacity() {
257
    return $this->unitsPropertySumById(0, 'capacity');
258
  }
259
260
  /**
261
   * Get count of units in UnitList by unit_id (or all units if unit_id == 0)
262
   *
263
   * @param int $unit_id - 0 - all units
264
   *
265
   * @return int
266
   */
267
  public function unitsCountById($unit_id = 0) {
268
    return $this->unitsPropertySumById($unit_id, 'count');
269
  }
270
271
  public function unitsPropertySumById($unit_id = 0, $propertyName = 'count') {
272
    $result = 0;
273
    foreach($this->mapUnitIdToDb as $unit) {
274
      if(!$unit_id || $unit->unitId == $unit_id) {
275
        $result += $unit->$propertyName;
276
      }
277
    }
278
279
    return $result;
280
  }
281
282
283
//  // TODO - revise it later
0 ignored issues
show
Unused Code Comprehensibility introduced by
39% 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...
284
//  public function _reset() {
285
//    //if(!empty($this->mapUnitIdToDb)) {
286
//    //  foreach($this->mapUnitIdToDb as $unit_id => $object) {
287
//    //    unset($this->mapUnitIdToDb[$unit_id]);
288
//    //  }
289
//    //}
290
//    unset($this->mapUnitIdToDb);
291
//    $this->mapUnitIdToDb = array();
292
//
293
//    //if(!empty($this->_container)) {
294
//    //  foreach($this->_container as $unit_db_id => $object) {
295
//    //    unset($this->_container[$unit_db_id]);
296
//    //  }
297
//    //}
298
//    unset($this->_container);
299
//    $this->_container = array();
300
//  }
301
302
303
  // TODO - DEBUG - REMOVE =============================================================================================
304
  public function _dump() {
305
    global $lang;
306
307
    print(__FILE__ . ':' . __LINE__ . "<br />");
308
    print("Located at " . $this->getLocationDbId() . " type " . $this->getLocationType() . "<br />");
309
310
    print('<table border="1">');
311
    print('<tr>');
312
313
    print('<th>');
314
    print('dbId');
315
    print('</th>');
316
317
    print('<th>');
318
    print('type');
319
    print('</th>');
320
321
    print('<th>');
322
    print('unitId');
323
    print('</th>');
324
325
    print('<th>');
326
    print('count');
327
    print('</th>');
328
329
    print('<th>');
330
    print('playerOwnerId');
331
    print('</th>');
332
333
    print('<th>');
334
    print('location');
335
    print('</th>');
336
337
    print('<th>');
338
    print('locationType');
339
    print('</th>');
340
341
    print('<th>');
342
    print('locationDbId');
343
    print('</th>');
344
345
    print('<th>');
346
    print('timeStart');
347
    print('</th>');
348
349
    print('<th>');
350
    print('timeFinish');
351
    print('</th>');
352
353
    print('</tr>');
354
355
    foreach($this->mapUnitIdToDb as $unit) {
356
      print('<tr>');
357
358
      print('<td>');
359
      print($unit->dbId);
360
      print('</td>');
361
362
      print('<td>');
363
      $type = $unit->getType();
364
      print("[{$type}] {$lang['tech'][$type]}");
365
      print('</td>');
366
367
      print('<td>');
368
      print("[{$unit->unitId}] {$lang['tech'][$unit->unitId]}");
369
      print('</td>');
370
371
      print('<td>');
372
      print($unit->count);
373
      print('</td>');
374
375
      print('<td>');
376
      print($unit->getPlayerOwnerId());
377
      print('</td>');
378
379
      print('<td>');
380
//      print($unit->location);
0 ignored issues
show
Unused Code Comprehensibility introduced by
75% 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...
381
      print('</td>');
382
383
      print('<td>');
384
      print($unit->getLocationType());
385
      print('</td>');
386
387
      print('<td>');
388
      print($unit->getLocationDbId());
389
      print('</td>');
390
391
      print('<td>');
392
      print($unit->getTimeStart());
393
      print('</td>');
394
395
      print('<td>');
396
      print($unit->getTimeFinish());
397
      print('</td>');
398
399
      print('</tr>');
400
    }
401
    print('</table>');
402
  }
403
404
405
  public function unitZeroDbId() {
406
    foreach($this->mapUnitIdToDb as $unit) {
407
      $unit->zeroDbId();
408
    }
409
  }
410
411
412
  public function unitZeroCount() {
413
    foreach($this->mapUnitIdToDb as $unit) {
414
      $unit->count = 0;
415
    }
416
  }
417
418
}
419