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