Issues (1369)

classes/classPersistent.php (7 issues)

1
<?php
2
/**
3
 * Created by Gorlum 29.10.2016 10:16
4
 */
5
6
/**
7
 *
8
 * Persistent is extension of class cacher and can save itself to DB
9
 * It's most usefull to hold basic structures as configuration, variables etc
10
 * Persistent pretty smart to handle one-level tables structures a-la "variable_name"+"variable_value"
11
 * Look supernova.sql to learn more
12
 * Also this class can holds default values for variables
13
 *
14
 * @package supernova
15
 *
16
 */
17
class classPersistent extends classCache {
18
  protected $table_name;
19
  protected $sql_index_field;
20
  protected $sql_value_field;
21
22
  protected $defaults = array();
23
24
  /**
25
   * List of fields which should have not empty values
26
   *
27
   * @var string[] $notEmptyFields [(str)fieldName => (str)fieldName, ...]
28
   */
29
  protected $notEmptyFields = [];
30
31
  /**
32
   * @var bool $force
33
   */
34
  protected $force = false;
35
36
  public function __construct($gamePrefix = 'sn_', $table_name = 'table') {
37
    parent::__construct("{$gamePrefix}{$table_name}_");
38
    $this->table_name = $table_name;
39
40
    $this->sql_index_field = "{$table_name}_name";
41
    $this->sql_value_field = "{$table_name}_value";
42
43
    if(!$this->_DB_LOADED) {
44
      $this->db_loadAll();
45
    }
46
  }
47
48
  public static function getInstance($gamePrefix = 'sn_', $table_name = '') {
49
    if (!isset(self::$cacheObject)) {
50
      $className = get_class();
51
      self::$cacheObject = new $className($gamePrefix, $table_name);
52
    }
53
    return self::$cacheObject;
54
  }
55
56
  /**
57
   * @param string $index
58
   *
59
   * @return string|null
60
   */
61
  public function db_loadItem($index) {
62
    $result = null;
63
    if($index) {
64
      $index_safe = SN::$db->db_escape($index);
65
      $queryResult = doquery("SELECT `{$this->sql_value_field}` FROM `{{{$this->table_name}}}` WHERE `{$this->sql_index_field}` = '{$index_safe}' FOR UPDATE", true);
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

65
      $queryResult = /** @scrutinizer ignore-deprecated */ doquery("SELECT `{$this->sql_value_field}` FROM `{{{$this->table_name}}}` WHERE `{$this->sql_index_field}` = '{$index_safe}' FOR UPDATE", true);
Loading history...
true of type true is incompatible with the type string expected by parameter $table of doquery(). ( Ignorable by Annotation )

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

65
      $queryResult = doquery("SELECT `{$this->sql_value_field}` FROM `{{{$this->table_name}}}` WHERE `{$this->sql_index_field}` = '{$index_safe}' FOR UPDATE", /** @scrutinizer ignore-type */ true);
Loading history...
66
      if(is_array($queryResult) && !empty($queryResult)) {
67
        $this->$index = $result = $queryResult[$this->sql_value_field];
68
      }
69
    }
70
71
    return $result;
72
  }
73
74
  public function db_loadAll() {
75
    $this->loadDefaults();
76
77
    $query = doquery("SELECT * FROM {{{$this->table_name}}} FOR UPDATE;");
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

77
    $query = /** @scrutinizer ignore-deprecated */ doquery("SELECT * FROM {{{$this->table_name}}} FOR UPDATE;");
Loading history...
78
    while($row = db_fetch($query)) {
0 ignored issues
show
Deprecated Code introduced by
The function db_fetch() has been deprecated. ( Ignorable by Annotation )

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

78
    while($row = /** @scrutinizer ignore-deprecated */ db_fetch($query)) {
Loading history...
79
      $this[$row[$this->sql_index_field]] = $row[$this->sql_value_field];
80
    }
81
82
    $this->_DB_LOADED = true;
0 ignored issues
show
Bug Best Practice introduced by
The property _DB_LOADED does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
83
  }
84
85
  public function loadDefaults() {
86
    foreach($this->defaults as $defName => $defValue) {
87
      $this->$defName = $defValue;
88
    }
89
  }
90
91
  public function db_saveAll() {
92
    $this->db_saveItem(array_combine(array_keys($this->defaults), array_fill(0, count($this->defaults), null)));
93
  }
94
95
  public function db_saveItem($item_list, $value = NULL) {
96
    if(empty($item_list)) {
97
      return;
98
    }
99
100
    !is_array($item_list) ? $item_list = array($item_list => $value) : false;
101
102
    // Сначала записываем данные в базу - что бы поймать все блокировки
103
    $qry = array();
104
    foreach($item_list as $item_name => $item_value) {
105
      if($item_name) {
106
        $item_value = SN::$db->db_escape($item_value === NULL ? $this->$item_name : $item_value);
107
        $item_name = SN::$db->db_escape($item_name);
108
        $qry[] = "('{$item_name}', '{$item_value}')";
109
      }
110
    }
111
    doquery("REPLACE INTO `{{" . $this->table_name . "}}` (`{$this->sql_index_field}`, `{$this->sql_value_field}`) VALUES " . implode(',', $qry) . ";");
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

111
    /** @scrutinizer ignore-deprecated */ doquery("REPLACE INTO `{{" . $this->table_name . "}}` (`{$this->sql_index_field}`, `{$this->sql_value_field}`) VALUES " . implode(',', $qry) . ";");
Loading history...
112
113
    // И только после взятия блокировок - меняем значения в кэше
114
    foreach($item_list as $item_name => $item_value) {
115
      if($item_name && $item_value !== null) {
116
        $this->__set($item_name, $item_value);
117
      }
118
    }
119
  }
120
121
  /**
122
   * Instructs cache to pass next operation to DB - whether it read or write
123
   *
124
   * This allows more transparency when accessing variables. So
125
   *    $this->db_loadItem('variable_name')
126
   * converts to
127
   *    $this->pass()->variable_name
128
   * Latest makes IDE aware of operation with variables and makes navigation and code refactoring (i.e. variable renaming) much easier
129
   * Same work with saving items directly to DB:
130
   *    $this->db_saveItem('variable_name', $value)
131
   * becomes
132
   *    $this->pass()->variable_name = $value;
133
   *
134
   * @return $this
135
   */
136
  public function pass() {
137
    $this->force = true;
138
139
    return $this;
140
  }
141
142
  public function __get($name) {
143
    if($this->force) {
144
      $this->force = false;
145
      $value = $this->db_loadItem($name);
146
    } else {
147
      $value = parent::__get($name);
148
    }
149
150
    if(isset($this->notEmptyFields[$name]) && empty($value) && isset($this->defaults[$name])) {
151
      $value = $this->defaults[$name];
152
    }
153
154
    return $value;
155
  }
156
157
  public function __set($name, $value) {
158
    if($this->force) {
159
      $this->force = false;
160
      $this->db_saveItem($name, $value);
161
    }
162
163
    parent::__set($name, $value);
164
  }
165
166
  public function __unset($name) {
167
    doquery('DELETE FROM `{{config}}` WHERE `config_name` = "' . SN::$db->db_escape($name) . '"');
0 ignored issues
show
Deprecated Code introduced by
The function doquery() has been deprecated. ( Ignorable by Annotation )

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

167
    /** @scrutinizer ignore-deprecated */ doquery('DELETE FROM `{{config}}` WHERE `config_name` = "' . SN::$db->db_escape($name) . '"');
Loading history...
168
169
    parent::__unset($name);
170
  }
171
172
}
173