Commit | Line | Data |
---|---|---|
158bd3ca | 1 | <?php |
a9229942 | 2 | |
158bd3ca | 3 | namespace wcf\data; |
a9229942 | 4 | |
158bd3ca TD |
5 | use wcf\system\WCF; |
6 | ||
7 | /** | |
8 | * Abstract class for all data holder classes. | |
a9229942 TD |
9 | * |
10 | * @author Marcel Werk | |
11 | * @copyright 2001-2019 WoltLab GmbH | |
12 | * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php> | |
13 | * @package WoltLabSuite\Core\Data | |
158bd3ca | 14 | */ |
a9229942 TD |
15 | abstract class DatabaseObject implements IIDObject, IStorableObject |
16 | { | |
17 | /** | |
18 | * database table for this object | |
19 | * @var string | |
20 | */ | |
21 | protected static $databaseTableName = ''; | |
22 | ||
23 | /** | |
24 | * indicates if database table index is an identity column | |
25 | * @var bool | |
26 | */ | |
27 | protected static $databaseTableIndexIsIdentity = true; | |
28 | ||
29 | /** | |
30 | * name of the primary index column | |
31 | * @var string | |
32 | */ | |
33 | protected static $databaseTableIndexName = ''; | |
34 | ||
35 | /** | |
36 | * sort field | |
37 | * @var mixed | |
38 | */ | |
39 | protected static $sortBy = null; | |
40 | ||
41 | /** | |
42 | * sort order | |
43 | * @var mixed | |
44 | */ | |
45 | protected static $sortOrder = null; | |
46 | ||
47 | /** | |
48 | * object data | |
49 | * @var array | |
50 | */ | |
51 | protected $data; | |
52 | ||
53 | /** | |
54 | * Creates a new instance of the DatabaseObject class. | |
55 | * | |
56 | * @param mixed $id | |
57 | * @param array $row | |
58 | * @param DatabaseObject $object | |
59 | */ | |
60 | public function __construct($id, ?array $row = null, ?self $object = null) | |
61 | { | |
62 | if ($id !== null) { | |
63 | $sql = "SELECT * | |
64 | FROM " . static::getDatabaseTableName() . " | |
65 | WHERE " . static::getDatabaseTableIndexName() . " = ?"; | |
66 | $statement = WCF::getDB()->prepareStatement($sql); | |
67 | $statement->execute([$id]); | |
68 | $row = $statement->fetchArray(); | |
69 | ||
70 | // enforce data type 'array' | |
71 | if ($row === false) { | |
72 | $row = []; | |
73 | } | |
74 | } elseif ($object !== null) { | |
75 | $row = $object->data; | |
76 | } | |
77 | ||
78 | $this->handleData($row); | |
79 | } | |
80 | ||
81 | /** | |
82 | * Stores the data of a database row. | |
83 | * | |
84 | * @param array $data | |
85 | */ | |
86 | protected function handleData($data) | |
87 | { | |
88 | // provide a logical false value for - assumed numeric - primary index | |
89 | if (!isset($data[static::getDatabaseTableIndexName()])) { | |
90 | $data[static::getDatabaseTableIndexName()] = 0; | |
91 | } | |
92 | ||
93 | $this->data = $data; | |
94 | } | |
95 | ||
96 | /** | |
97 | * @inheritDoc | |
98 | */ | |
99 | public function __get($name) | |
100 | { | |
101 | if (isset($this->data[$name])) { | |
102 | return $this->data[$name]; | |
103 | } else { | |
104 | return; | |
105 | } | |
106 | } | |
107 | ||
108 | /** | |
109 | * Returns the id of the object. | |
110 | * | |
111 | * @return int | |
112 | */ | |
113 | public function getObjectID() | |
114 | { | |
115 | return $this->data[static::getDatabaseTableIndexName()]; | |
116 | } | |
117 | ||
118 | /** | |
119 | * @inheritDoc | |
120 | */ | |
121 | public function __isset($name) | |
122 | { | |
123 | return isset($this->data[$name]); | |
124 | } | |
125 | ||
126 | /** | |
127 | * @inheritDoc | |
128 | */ | |
129 | public function getData() | |
130 | { | |
131 | return $this->data; | |
132 | } | |
133 | ||
134 | /** | |
135 | * @inheritDoc | |
136 | */ | |
137 | public static function getDatabaseTableName() | |
138 | { | |
139 | $className = \get_called_class(); | |
140 | $classParts = \explode('\\', $className); | |
141 | ||
142 | if (static::$databaseTableName !== '') { | |
143 | return $classParts[0] . WCF_N . '_' . static::$databaseTableName; | |
144 | } | |
145 | ||
146 | static $databaseTableNames = []; | |
147 | if (!isset($databaseTableNames[$className])) { | |
148 | $databaseTableNames[$className] = $classParts[0] . WCF_N . '_' . \strtolower(\implode( | |
149 | '_', | |
150 | \preg_split( | |
151 | '~(?=[A-Z](?=[a-z]))~', | |
152 | \array_pop($classParts), | |
153 | -1, | |
154 | \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY | |
155 | ) | |
156 | )); | |
157 | } | |
158 | ||
159 | return $databaseTableNames[$className]; | |
160 | } | |
161 | ||
162 | /** | |
163 | * @inheritDoc | |
164 | */ | |
165 | public static function getDatabaseTableAlias() | |
166 | { | |
167 | if (static::$databaseTableName !== '') { | |
168 | return static::$databaseTableName; | |
169 | } | |
170 | ||
171 | $className = \get_called_class(); | |
172 | static $databaseTableAliases = []; | |
173 | if (!isset($databaseTableAliases[$className])) { | |
174 | $classParts = \explode('\\', $className); | |
175 | $databaseTableAliases[$className] = \strtolower(\implode( | |
176 | '_', | |
177 | \preg_split( | |
178 | '~(?=[A-Z](?=[a-z]))~', | |
179 | \array_pop($classParts), | |
180 | -1, | |
181 | \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY | |
182 | ) | |
183 | )); | |
184 | } | |
185 | ||
186 | return $databaseTableAliases[$className]; | |
187 | } | |
188 | ||
189 | /** | |
190 | * @inheritDoc | |
191 | */ | |
192 | public static function getDatabaseTableIndexIsIdentity() | |
193 | { | |
194 | return static::$databaseTableIndexIsIdentity; | |
195 | } | |
196 | ||
197 | /** | |
198 | * @inheritDoc | |
199 | */ | |
200 | public static function getDatabaseTableIndexName() | |
201 | { | |
202 | if (static::$databaseTableIndexName !== '') { | |
203 | return static::$databaseTableIndexName; | |
204 | } | |
205 | ||
206 | static $databaseTableIndexName = null; | |
207 | if ($databaseTableIndexName === null) { | |
208 | $className = \explode('\\', \get_called_class()); | |
209 | $parts = \preg_split( | |
210 | '~(?=[A-Z](?=[a-z]))~', | |
211 | \array_pop($className), | |
212 | -1, | |
213 | \PREG_SPLIT_DELIM_CAPTURE | \PREG_SPLIT_NO_EMPTY | |
214 | ); | |
215 | $databaseTableIndexName = \strtolower(\array_pop($parts)) . 'ID'; | |
216 | } | |
217 | ||
218 | return $databaseTableIndexName; | |
219 | } | |
220 | ||
221 | /** | |
222 | * Sorts a list of database objects. | |
223 | * | |
224 | * @param DatabaseObject[] $objects | |
225 | * @param mixed $sortBy | |
226 | * @param string $sortOrder | |
227 | * @param bool $maintainIndexAssociation | |
228 | */ | |
229 | public static function sort(&$objects, $sortBy, $sortOrder = 'ASC', $maintainIndexAssociation = true) | |
230 | { | |
231 | $sortArray = $objects2 = []; | |
232 | foreach ($objects as $idx => $obj) { | |
233 | /** @noinspection PhpVariableVariableInspection */ | |
234 | $sortArray[$idx] = $obj->{$sortBy}; | |
235 | ||
236 | // array_multisort will drop index association if key is not a string | |
237 | if ($maintainIndexAssociation) { | |
238 | $objects2[$idx . 'x'] = $obj; | |
239 | } | |
240 | } | |
241 | ||
242 | if ($maintainIndexAssociation) { | |
243 | $objects = []; | |
244 | \array_multisort($sortArray, $sortOrder == 'ASC' ? \SORT_ASC : \SORT_DESC, $objects2); | |
245 | ||
246 | $objects = []; | |
247 | foreach ($objects2 as $idx => $obj) { | |
248 | $objects[\substr($idx, 0, -1)] = $obj; | |
249 | } | |
250 | } else { | |
251 | \array_multisort($sortArray, $sortOrder == 'ASC' ? \SORT_ASC : \SORT_DESC, $objects); | |
252 | } | |
253 | } | |
004426c2 | 254 | } |