Merge branch '5.3'
[GitHub/WoltLab/WCF.git] / wcfsetup / install / files / lib / data / DatabaseObjectEditor.class.php
1 <?php
2
3 namespace wcf\data;
4
5 use wcf\system\database\exception\DatabaseQueryExecutionException;
6 use wcf\system\database\util\PreparedStatementConditionBuilder;
7 use wcf\system\WCF;
8
9 /**
10 * Basic implementation for object editors following the decorator pattern.
11 *
12 * @author Marcel Werk
13 * @copyright 2001-2019 WoltLab GmbH
14 * @license GNU Lesser General Public License <http://opensource.org/licenses/lgpl-license.php>
15 * @package WoltLabSuite\Core\Data
16 */
17 abstract class DatabaseObjectEditor extends DatabaseObjectDecorator implements IEditableObject
18 {
19 /**
20 * @inheritDoc
21 */
22 public static function create(array $parameters = [])
23 {
24 $keys = $values = '';
25 $statementParameters = [];
26 foreach ($parameters as $key => $value) {
27 if (!empty($keys)) {
28 $keys .= ',';
29 $values .= ',';
30 }
31
32 $keys .= $key;
33 $values .= '?';
34 $statementParameters[] = $value;
35 }
36
37 // save object
38 $sql = "INSERT INTO " . static::getDatabaseTableName() . "
39 (" . $keys . ")
40 VALUES (" . $values . ")";
41 $statement = WCF::getDB()->prepareStatement($sql);
42 $statement->execute($statementParameters);
43
44 // return new object
45 if (static::getDatabaseTableIndexIsIdentity()) {
46 $id = WCF::getDB()->getInsertID(static::getDatabaseTableName(), static::getDatabaseTableIndexName());
47 } else {
48 $id = $parameters[static::getDatabaseTableIndexName()];
49 }
50
51 return new static::$baseClass($id);
52 }
53
54 /**
55 * @inheritDoc
56 */
57 public function update(array $parameters = [])
58 {
59 if (empty($parameters)) {
60 return;
61 }
62
63 $updateSQL = '';
64 $statementParameters = [];
65 foreach ($parameters as $key => $value) {
66 if (!empty($updateSQL)) {
67 $updateSQL .= ', ';
68 }
69 $updateSQL .= $key . ' = ?';
70 $statementParameters[] = $value;
71 }
72 $statementParameters[] = $this->getObjectID();
73
74 $sql = "UPDATE " . static::getDatabaseTableName() . "
75 SET " . $updateSQL . "
76 WHERE " . static::getDatabaseTableIndexName() . " = ?";
77 $statement = WCF::getDB()->prepareStatement($sql);
78 $statement->execute($statementParameters);
79 }
80
81 /**
82 * @inheritDoc
83 */
84 public function updateCounters(array $counters = [])
85 {
86 if (empty($counters)) {
87 return;
88 }
89
90 $updateSQL = '';
91 $statementParameters = [];
92 foreach ($counters as $key => $value) {
93 if (!empty($updateSQL)) {
94 $updateSQL .= ', ';
95 }
96 $updateSQL .= $key . ' = ' . $key . ' + ?';
97 $statementParameters[] = $value;
98 }
99 $statementParameters[] = $this->getObjectID();
100
101 $sql = "UPDATE " . static::getDatabaseTableName() . "
102 SET " . $updateSQL . "
103 WHERE " . static::getDatabaseTableIndexName() . " = ?";
104 $statement = WCF::getDB()->prepareStatement($sql);
105 $statement->execute($statementParameters);
106 }
107
108 /**
109 * @inheritDoc
110 */
111 public function delete()
112 {
113 static::deleteAll([$this->getObjectID()]);
114 }
115
116 /**
117 * @inheritDoc
118 */
119 public static function deleteAll(array $objectIDs = [])
120 {
121 $affectedCount = 0;
122
123 $itemsPerLoop = 1000;
124 $loopCount = \ceil(\count($objectIDs) / $itemsPerLoop);
125
126 WCF::getDB()->beginTransaction();
127 for ($i = 0; $i < $loopCount; $i++) {
128 $batchObjectIDs = \array_slice($objectIDs, $i * $itemsPerLoop, $itemsPerLoop);
129
130 $conditionBuilder = new PreparedStatementConditionBuilder();
131 $conditionBuilder->add(static::getDatabaseTableIndexName() . ' IN (?)', [$batchObjectIDs]);
132
133 $sql = "DELETE FROM " . static::getDatabaseTableName() . "
134 " . $conditionBuilder;
135 $statement = WCF::getDB()->prepareStatement($sql);
136 $statement->execute($conditionBuilder->getParameters());
137 $affectedCount += $statement->getAffectedRows();
138 }
139 WCF::getDB()->commitTransaction();
140
141 return $affectedCount;
142 }
143
144 /**
145 * Creates a new object, returns null if the row already exists.
146 *
147 * @param array $parameters
148 * @return IStorableObject|null
149 * @since 5.3
150 */
151 public static function createOrIgnore(array $parameters = [])
152 {
153 try {
154 return static::create($parameters);
155 } catch (DatabaseQueryExecutionException $e) {
156 // Error code 23000 = duplicate key
157 if ($e->getCode() == '23000' && $e->getDriverCode() == '1062') {
158 return;
159 }
160
161 throw $e;
162 }
163 }
164 }