Passed
Push — master ( c1368b...bc6a5e )
by Joas
13:04 queued 17s
created
lib/public/IDBConnection.php 1 patch
Indentation   +254 added lines, -254 removed lines patch added patch discarded remove patch
@@ -49,258 +49,258 @@
 block discarded – undo
49 49
  */
50 50
 interface IDBConnection {
51 51
 
52
-	const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
53
-	const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';
54
-	const ADD_MISSING_COLUMNS_EVENT = self::class . '::ADD_MISSING_COLUMNS';
55
-	const CHECK_MISSING_COLUMNS_EVENT = self::class . '::CHECK_MISSING_COLUMNS';
56
-
57
-	/**
58
-	 * Gets the QueryBuilder for the connection.
59
-	 *
60
-	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
61
-	 * @since 8.2.0
62
-	 */
63
-	public function getQueryBuilder();
64
-
65
-	/**
66
-	 * Used to abstract the ownCloud database access away
67
-	 * @param string $sql the sql query with ? placeholder for params
68
-	 * @param int $limit the maximum number of rows
69
-	 * @param int $offset from which row we want to start
70
-	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
71
-	 * @since 6.0.0
72
-	 */
73
-	public function prepare($sql, $limit=null, $offset=null);
74
-
75
-	/**
76
-	 * Executes an, optionally parameterized, SQL query.
77
-	 *
78
-	 * If the query is parameterized, a prepared statement is used.
79
-	 * If an SQLLogger is configured, the execution is logged.
80
-	 *
81
-	 * @param string $query The SQL query to execute.
82
-	 * @param string[] $params The parameters to bind to the query, if any.
83
-	 * @param array $types The types the previous parameters are in.
84
-	 * @return \Doctrine\DBAL\Driver\Statement The executed statement.
85
-	 * @since 8.0.0
86
-	 */
87
-	public function executeQuery($query, array $params = [], $types = []);
88
-
89
-	/**
90
-	 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
91
-	 * and returns the number of affected rows.
92
-	 *
93
-	 * This method supports PDO binding types as well as DBAL mapping types.
94
-	 *
95
-	 * @param string $query The SQL query.
96
-	 * @param array $params The query parameters.
97
-	 * @param array $types The parameter types.
98
-	 * @return integer The number of affected rows.
99
-	 * @since 8.0.0
100
-	 */
101
-	public function executeUpdate($query, array $params = [], array $types = []);
102
-
103
-	/**
104
-	 * Used to get the id of the just inserted element
105
-	 * @param string $table the name of the table where we inserted the item
106
-	 * @return int the id of the inserted element
107
-	 * @since 6.0.0
108
-	 */
109
-	public function lastInsertId($table = null);
110
-
111
-	/**
112
-	 * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
113
-	 * it is needed that there is also a unique constraint on the values. Then this method will
114
-	 * catch the exception and return 0.
115
-	 *
116
-	 * @param string $table The table name (will replace *PREFIX* with the actual prefix)
117
-	 * @param array $input data that should be inserted into the table  (column name => value)
118
-	 * @param array|null $compare List of values that should be checked for "if not exists"
119
-	 *				If this is null or an empty array, all keys of $input will be compared
120
-	 *				Please note: text fields (clob) must not be used in the compare array
121
-	 * @return int number of inserted rows
122
-	 * @throws \Doctrine\DBAL\DBALException
123
-	 * @since 6.0.0 - parameter $compare was added in 8.1.0, return type changed from boolean in 8.1.0
124
-	 * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
125
-	 */
126
-	public function insertIfNotExist($table, $input, array $compare = null);
127
-
128
-
129
-	/**
130
-	 *
131
-	 * Insert a row if the row does not exist. Eventual conflicts during insert will be ignored.
132
-	 *
133
-	 * Implementation is not fully finished and should not be used!
134
-	 *
135
-	 * @param string $table The table name (will replace *PREFIX* with the actual prefix)
136
-	 * @param array $values data that should be inserted into the table  (column name => value)
137
-	 * @return int number of inserted rows
138
-	 * @since 16.0.0
139
-	 */
140
-	public function insertIgnoreConflict(string $table,array $values) : int;
141
-
142
-	/**
143
-	 * Insert or update a row value
144
-	 *
145
-	 * @param string $table
146
-	 * @param array $keys (column name => value)
147
-	 * @param array $values (column name => value)
148
-	 * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
149
-	 * @return int number of new rows
150
-	 * @throws \Doctrine\DBAL\DBALException
151
-	 * @throws PreconditionNotMetException
152
-	 * @since 9.0.0
153
-	 */
154
-	public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []);
155
-
156
-	/**
157
-	 * Create an exclusive read+write lock on a table
158
-	 *
159
-	 * Important Note: Due to the nature how locks work on different DBs, it is
160
-	 * only possible to lock one table at a time. You should also NOT start a
161
-	 * transaction while holding a lock.
162
-	 *
163
-	 * @param string $tableName
164
-	 * @since 9.1.0
165
-	 */
166
-	public function lockTable($tableName);
167
-
168
-	/**
169
-	 * Release a previous acquired lock again
170
-	 *
171
-	 * @since 9.1.0
172
-	 */
173
-	public function unlockTable();
174
-
175
-	/**
176
-	 * Start a transaction
177
-	 * @since 6.0.0
178
-	 */
179
-	public function beginTransaction();
180
-
181
-	/**
182
-	 * Check if a transaction is active
183
-	 *
184
-	 * @return bool
185
-	 * @since 8.2.0
186
-	 */
187
-	public function inTransaction();
188
-
189
-	/**
190
-	 * Commit the database changes done during a transaction that is in progress
191
-	 * @since 6.0.0
192
-	 */
193
-	public function commit();
194
-
195
-	/**
196
-	 * Rollback the database changes done during a transaction that is in progress
197
-	 * @since 6.0.0
198
-	 */
199
-	public function rollBack();
200
-
201
-	/**
202
-	 * Gets the error code and message as a string for logging
203
-	 * @return string
204
-	 * @since 6.0.0
205
-	 */
206
-	public function getError();
207
-
208
-	/**
209
-	 * Fetch the SQLSTATE associated with the last database operation.
210
-	 *
211
-	 * @return integer The last error code.
212
-	 * @since 8.0.0
213
-	 */
214
-	public function errorCode();
215
-
216
-	/**
217
-	 * Fetch extended error information associated with the last database operation.
218
-	 *
219
-	 * @return array The last error information.
220
-	 * @since 8.0.0
221
-	 */
222
-	public function errorInfo();
223
-
224
-	/**
225
-	 * Establishes the connection with the database.
226
-	 *
227
-	 * @return bool
228
-	 * @since 8.0.0
229
-	 */
230
-	public function connect();
231
-
232
-	/**
233
-	 * Close the database connection
234
-	 * @since 8.0.0
235
-	 */
236
-	public function close();
237
-
238
-	/**
239
-	 * Quotes a given input parameter.
240
-	 *
241
-	 * @param mixed $input Parameter to be quoted.
242
-	 * @param int $type Type of the parameter.
243
-	 * @return string The quoted parameter.
244
-	 * @since 8.0.0
245
-	 */
246
-	public function quote($input, $type = IQueryBuilder::PARAM_STR);
247
-
248
-	/**
249
-	 * Gets the DatabasePlatform instance that provides all the metadata about
250
-	 * the platform this driver connects to.
251
-	 *
252
-	 * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
253
-	 * @since 8.0.0
254
-	 */
255
-	public function getDatabasePlatform();
256
-
257
-	/**
258
-	 * Drop a table from the database if it exists
259
-	 *
260
-	 * @param string $table table name without the prefix
261
-	 * @since 8.0.0
262
-	 */
263
-	public function dropTable($table);
264
-
265
-	/**
266
-	 * Check if a table exists
267
-	 *
268
-	 * @param string $table table name without the prefix
269
-	 * @return bool
270
-	 * @since 8.0.0
271
-	 */
272
-	public function tableExists($table);
273
-
274
-	/**
275
-	 * Escape a parameter to be used in a LIKE query
276
-	 *
277
-	 * @param string $param
278
-	 * @return string
279
-	 * @since 9.0.0
280
-	 */
281
-	public function escapeLikeParameter($param);
282
-
283
-	/**
284
-	 * Check whether or not the current database support 4byte wide unicode
285
-	 *
286
-	 * @return bool
287
-	 * @since 11.0.0
288
-	 */
289
-	public function supports4ByteText();
290
-
291
-	/**
292
-	 * Create the schema of the connected database
293
-	 *
294
-	 * @return Schema
295
-	 * @since 13.0.0
296
-	 */
297
-	public function createSchema();
298
-
299
-	/**
300
-	 * Migrate the database to the given schema
301
-	 *
302
-	 * @param Schema $toSchema
303
-	 * @since 13.0.0
304
-	 */
305
-	public function migrateToSchema(Schema $toSchema);
52
+    const ADD_MISSING_INDEXES_EVENT = self::class . '::ADD_MISSING_INDEXES';
53
+    const CHECK_MISSING_INDEXES_EVENT = self::class . '::CHECK_MISSING_INDEXES';
54
+    const ADD_MISSING_COLUMNS_EVENT = self::class . '::ADD_MISSING_COLUMNS';
55
+    const CHECK_MISSING_COLUMNS_EVENT = self::class . '::CHECK_MISSING_COLUMNS';
56
+
57
+    /**
58
+     * Gets the QueryBuilder for the connection.
59
+     *
60
+     * @return \OCP\DB\QueryBuilder\IQueryBuilder
61
+     * @since 8.2.0
62
+     */
63
+    public function getQueryBuilder();
64
+
65
+    /**
66
+     * Used to abstract the ownCloud database access away
67
+     * @param string $sql the sql query with ? placeholder for params
68
+     * @param int $limit the maximum number of rows
69
+     * @param int $offset from which row we want to start
70
+     * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
71
+     * @since 6.0.0
72
+     */
73
+    public function prepare($sql, $limit=null, $offset=null);
74
+
75
+    /**
76
+     * Executes an, optionally parameterized, SQL query.
77
+     *
78
+     * If the query is parameterized, a prepared statement is used.
79
+     * If an SQLLogger is configured, the execution is logged.
80
+     *
81
+     * @param string $query The SQL query to execute.
82
+     * @param string[] $params The parameters to bind to the query, if any.
83
+     * @param array $types The types the previous parameters are in.
84
+     * @return \Doctrine\DBAL\Driver\Statement The executed statement.
85
+     * @since 8.0.0
86
+     */
87
+    public function executeQuery($query, array $params = [], $types = []);
88
+
89
+    /**
90
+     * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
91
+     * and returns the number of affected rows.
92
+     *
93
+     * This method supports PDO binding types as well as DBAL mapping types.
94
+     *
95
+     * @param string $query The SQL query.
96
+     * @param array $params The query parameters.
97
+     * @param array $types The parameter types.
98
+     * @return integer The number of affected rows.
99
+     * @since 8.0.0
100
+     */
101
+    public function executeUpdate($query, array $params = [], array $types = []);
102
+
103
+    /**
104
+     * Used to get the id of the just inserted element
105
+     * @param string $table the name of the table where we inserted the item
106
+     * @return int the id of the inserted element
107
+     * @since 6.0.0
108
+     */
109
+    public function lastInsertId($table = null);
110
+
111
+    /**
112
+     * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
113
+     * it is needed that there is also a unique constraint on the values. Then this method will
114
+     * catch the exception and return 0.
115
+     *
116
+     * @param string $table The table name (will replace *PREFIX* with the actual prefix)
117
+     * @param array $input data that should be inserted into the table  (column name => value)
118
+     * @param array|null $compare List of values that should be checked for "if not exists"
119
+     *				If this is null or an empty array, all keys of $input will be compared
120
+     *				Please note: text fields (clob) must not be used in the compare array
121
+     * @return int number of inserted rows
122
+     * @throws \Doctrine\DBAL\DBALException
123
+     * @since 6.0.0 - parameter $compare was added in 8.1.0, return type changed from boolean in 8.1.0
124
+     * @deprecated 15.0.0 - use unique index and "try { $db->insert() } catch (UniqueConstraintViolationException $e) {}" instead, because it is more reliable and does not have the risk for deadlocks - see https://github.com/nextcloud/server/pull/12371
125
+     */
126
+    public function insertIfNotExist($table, $input, array $compare = null);
127
+
128
+
129
+    /**
130
+     *
131
+     * Insert a row if the row does not exist. Eventual conflicts during insert will be ignored.
132
+     *
133
+     * Implementation is not fully finished and should not be used!
134
+     *
135
+     * @param string $table The table name (will replace *PREFIX* with the actual prefix)
136
+     * @param array $values data that should be inserted into the table  (column name => value)
137
+     * @return int number of inserted rows
138
+     * @since 16.0.0
139
+     */
140
+    public function insertIgnoreConflict(string $table,array $values) : int;
141
+
142
+    /**
143
+     * Insert or update a row value
144
+     *
145
+     * @param string $table
146
+     * @param array $keys (column name => value)
147
+     * @param array $values (column name => value)
148
+     * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
149
+     * @return int number of new rows
150
+     * @throws \Doctrine\DBAL\DBALException
151
+     * @throws PreconditionNotMetException
152
+     * @since 9.0.0
153
+     */
154
+    public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []);
155
+
156
+    /**
157
+     * Create an exclusive read+write lock on a table
158
+     *
159
+     * Important Note: Due to the nature how locks work on different DBs, it is
160
+     * only possible to lock one table at a time. You should also NOT start a
161
+     * transaction while holding a lock.
162
+     *
163
+     * @param string $tableName
164
+     * @since 9.1.0
165
+     */
166
+    public function lockTable($tableName);
167
+
168
+    /**
169
+     * Release a previous acquired lock again
170
+     *
171
+     * @since 9.1.0
172
+     */
173
+    public function unlockTable();
174
+
175
+    /**
176
+     * Start a transaction
177
+     * @since 6.0.0
178
+     */
179
+    public function beginTransaction();
180
+
181
+    /**
182
+     * Check if a transaction is active
183
+     *
184
+     * @return bool
185
+     * @since 8.2.0
186
+     */
187
+    public function inTransaction();
188
+
189
+    /**
190
+     * Commit the database changes done during a transaction that is in progress
191
+     * @since 6.0.0
192
+     */
193
+    public function commit();
194
+
195
+    /**
196
+     * Rollback the database changes done during a transaction that is in progress
197
+     * @since 6.0.0
198
+     */
199
+    public function rollBack();
200
+
201
+    /**
202
+     * Gets the error code and message as a string for logging
203
+     * @return string
204
+     * @since 6.0.0
205
+     */
206
+    public function getError();
207
+
208
+    /**
209
+     * Fetch the SQLSTATE associated with the last database operation.
210
+     *
211
+     * @return integer The last error code.
212
+     * @since 8.0.0
213
+     */
214
+    public function errorCode();
215
+
216
+    /**
217
+     * Fetch extended error information associated with the last database operation.
218
+     *
219
+     * @return array The last error information.
220
+     * @since 8.0.0
221
+     */
222
+    public function errorInfo();
223
+
224
+    /**
225
+     * Establishes the connection with the database.
226
+     *
227
+     * @return bool
228
+     * @since 8.0.0
229
+     */
230
+    public function connect();
231
+
232
+    /**
233
+     * Close the database connection
234
+     * @since 8.0.0
235
+     */
236
+    public function close();
237
+
238
+    /**
239
+     * Quotes a given input parameter.
240
+     *
241
+     * @param mixed $input Parameter to be quoted.
242
+     * @param int $type Type of the parameter.
243
+     * @return string The quoted parameter.
244
+     * @since 8.0.0
245
+     */
246
+    public function quote($input, $type = IQueryBuilder::PARAM_STR);
247
+
248
+    /**
249
+     * Gets the DatabasePlatform instance that provides all the metadata about
250
+     * the platform this driver connects to.
251
+     *
252
+     * @return \Doctrine\DBAL\Platforms\AbstractPlatform The database platform.
253
+     * @since 8.0.0
254
+     */
255
+    public function getDatabasePlatform();
256
+
257
+    /**
258
+     * Drop a table from the database if it exists
259
+     *
260
+     * @param string $table table name without the prefix
261
+     * @since 8.0.0
262
+     */
263
+    public function dropTable($table);
264
+
265
+    /**
266
+     * Check if a table exists
267
+     *
268
+     * @param string $table table name without the prefix
269
+     * @return bool
270
+     * @since 8.0.0
271
+     */
272
+    public function tableExists($table);
273
+
274
+    /**
275
+     * Escape a parameter to be used in a LIKE query
276
+     *
277
+     * @param string $param
278
+     * @return string
279
+     * @since 9.0.0
280
+     */
281
+    public function escapeLikeParameter($param);
282
+
283
+    /**
284
+     * Check whether or not the current database support 4byte wide unicode
285
+     *
286
+     * @return bool
287
+     * @since 11.0.0
288
+     */
289
+    public function supports4ByteText();
290
+
291
+    /**
292
+     * Create the schema of the connected database
293
+     *
294
+     * @return Schema
295
+     * @since 13.0.0
296
+     */
297
+    public function createSchema();
298
+
299
+    /**
300
+     * Migrate the database to the given schema
301
+     *
302
+     * @param Schema $toSchema
303
+     * @since 13.0.0
304
+     */
305
+    public function migrateToSchema(Schema $toSchema);
306 306
 }
Please login to merge, or discard this patch.
lib/public/Comments/IComment.php 1 patch
Indentation   +219 added lines, -219 removed lines patch added patch discarded remove patch
@@ -34,250 +34,250 @@
 block discarded – undo
34 34
  * @since 9.0.0
35 35
  */
36 36
 interface IComment {
37
-	const MAX_MESSAGE_LENGTH = 1000;
37
+    const MAX_MESSAGE_LENGTH = 1000;
38 38
 
39
-	/**
40
-	 * returns the ID of the comment
41
-	 *
42
-	 * It may return an empty string, if the comment was not stored.
43
-	 * It is expected that the concrete Comment implementation gives an ID
44
-	 * by itself (e.g. after saving).
45
-	 *
46
-	 * @return string
47
-	 * @since 9.0.0
48
-	 */
49
-	public function getId();
39
+    /**
40
+     * returns the ID of the comment
41
+     *
42
+     * It may return an empty string, if the comment was not stored.
43
+     * It is expected that the concrete Comment implementation gives an ID
44
+     * by itself (e.g. after saving).
45
+     *
46
+     * @return string
47
+     * @since 9.0.0
48
+     */
49
+    public function getId();
50 50
 
51
-	/**
52
-	 * sets the ID of the comment and returns itself
53
-	 *
54
-	 * It is only allowed to set the ID only, if the current id is an empty
55
-	 * string (which means it is not stored in a database, storage or whatever
56
-	 * the concrete implementation does), or vice versa. Changing a given ID is
57
-	 * not permitted and must result in an IllegalIDChangeException.
58
-	 *
59
-	 * @param string $id
60
-	 * @return IComment
61
-	 * @throws IllegalIDChangeException
62
-	 * @since 9.0.0
63
-	 */
64
-	public function setId($id);
51
+    /**
52
+     * sets the ID of the comment and returns itself
53
+     *
54
+     * It is only allowed to set the ID only, if the current id is an empty
55
+     * string (which means it is not stored in a database, storage or whatever
56
+     * the concrete implementation does), or vice versa. Changing a given ID is
57
+     * not permitted and must result in an IllegalIDChangeException.
58
+     *
59
+     * @param string $id
60
+     * @return IComment
61
+     * @throws IllegalIDChangeException
62
+     * @since 9.0.0
63
+     */
64
+    public function setId($id);
65 65
 
66
-	/**
67
-	 * returns the parent ID of the comment
68
-	 *
69
-	 * @return string
70
-	 * @since 9.0.0
71
-	 */
72
-	public function getParentId();
66
+    /**
67
+     * returns the parent ID of the comment
68
+     *
69
+     * @return string
70
+     * @since 9.0.0
71
+     */
72
+    public function getParentId();
73 73
 
74
-	/**
75
-	 * sets the parent ID and returns itself
76
-	 * @param string $parentId
77
-	 * @return IComment
78
-	 * @since 9.0.0
79
-	 */
80
-	public function setParentId($parentId);
74
+    /**
75
+     * sets the parent ID and returns itself
76
+     * @param string $parentId
77
+     * @return IComment
78
+     * @since 9.0.0
79
+     */
80
+    public function setParentId($parentId);
81 81
 
82
-	/**
83
-	 * returns the topmost parent ID of the comment
84
-	 *
85
-	 * @return string
86
-	 * @since 9.0.0
87
-	 */
88
-	public function getTopmostParentId();
82
+    /**
83
+     * returns the topmost parent ID of the comment
84
+     *
85
+     * @return string
86
+     * @since 9.0.0
87
+     */
88
+    public function getTopmostParentId();
89 89
 
90 90
 
91
-	/**
92
-	 * sets the topmost parent ID and returns itself
93
-	 *
94
-	 * @param string $id
95
-	 * @return IComment
96
-	 * @since 9.0.0
97
-	 */
98
-	public function setTopmostParentId($id);
91
+    /**
92
+     * sets the topmost parent ID and returns itself
93
+     *
94
+     * @param string $id
95
+     * @return IComment
96
+     * @since 9.0.0
97
+     */
98
+    public function setTopmostParentId($id);
99 99
 
100
-	/**
101
-	 * returns the number of children
102
-	 *
103
-	 * @return int
104
-	 * @since 9.0.0
105
-	 */
106
-	public function getChildrenCount();
100
+    /**
101
+     * returns the number of children
102
+     *
103
+     * @return int
104
+     * @since 9.0.0
105
+     */
106
+    public function getChildrenCount();
107 107
 
108
-	/**
109
-	 * sets the number of children
110
-	 *
111
-	 * @param int $count
112
-	 * @return IComment
113
-	 * @since 9.0.0
114
-	 */
115
-	public function setChildrenCount($count);
108
+    /**
109
+     * sets the number of children
110
+     *
111
+     * @param int $count
112
+     * @return IComment
113
+     * @since 9.0.0
114
+     */
115
+    public function setChildrenCount($count);
116 116
 
117
-	/**
118
-	 * returns the message of the comment
119
-	 *
120
-	 * @return string
121
-	 * @since 9.0.0
122
-	 */
123
-	public function getMessage();
117
+    /**
118
+     * returns the message of the comment
119
+     *
120
+     * @return string
121
+     * @since 9.0.0
122
+     */
123
+    public function getMessage();
124 124
 
125
-	/**
126
-	 * sets the message of the comment and returns itself
127
-	 *
128
-	 * When the given message length exceeds MAX_MESSAGE_LENGTH an
129
-	 * MessageTooLongException shall be thrown.
130
-	 *
131
-	 * @param string $message
132
-	 * @param int $maxLength
133
-	 * @return IComment
134
-	 * @throws MessageTooLongException
135
-	 * @since 9.0.0 - $maxLength added in 16.0.2
136
-	 */
137
-	public function setMessage($message, $maxLength = self::MAX_MESSAGE_LENGTH);
125
+    /**
126
+     * sets the message of the comment and returns itself
127
+     *
128
+     * When the given message length exceeds MAX_MESSAGE_LENGTH an
129
+     * MessageTooLongException shall be thrown.
130
+     *
131
+     * @param string $message
132
+     * @param int $maxLength
133
+     * @return IComment
134
+     * @throws MessageTooLongException
135
+     * @since 9.0.0 - $maxLength added in 16.0.2
136
+     */
137
+    public function setMessage($message, $maxLength = self::MAX_MESSAGE_LENGTH);
138 138
 
139
-	/**
140
-	 * returns an array containing mentions that are included in the comment
141
-	 *
142
-	 * @return array each mention provides a 'type' and an 'id', see example below
143
-	 * @since 11.0.0
144
-	 *
145
-	 * The return array looks like:
146
-	 * [
147
-	 *   [
148
-	 *     'type' => 'user',
149
-	 *     'id' => 'citizen4'
150
-	 *   ],
151
-	 *   [
152
-	 *     'type' => 'group',
153
-	 *     'id' => 'media'
154
-	 *   ],
155
-	 *   …
156
-	 * ]
157
-	 *
158
-	 */
159
-	public function getMentions();
139
+    /**
140
+     * returns an array containing mentions that are included in the comment
141
+     *
142
+     * @return array each mention provides a 'type' and an 'id', see example below
143
+     * @since 11.0.0
144
+     *
145
+     * The return array looks like:
146
+     * [
147
+     *   [
148
+     *     'type' => 'user',
149
+     *     'id' => 'citizen4'
150
+     *   ],
151
+     *   [
152
+     *     'type' => 'group',
153
+     *     'id' => 'media'
154
+     *   ],
155
+     *   …
156
+     * ]
157
+     *
158
+     */
159
+    public function getMentions();
160 160
 
161
-	/**
162
-	 * returns the verb of the comment
163
-	 *
164
-	 * @return string
165
-	 * @since 9.0.0
166
-	 */
167
-	public function getVerb();
161
+    /**
162
+     * returns the verb of the comment
163
+     *
164
+     * @return string
165
+     * @since 9.0.0
166
+     */
167
+    public function getVerb();
168 168
 
169
-	/**
170
-	 * sets the verb of the comment, e.g. 'comment' or 'like'
171
-	 *
172
-	 * @param string $verb
173
-	 * @return IComment
174
-	 * @since 9.0.0
175
-	 */
176
-	public function setVerb($verb);
169
+    /**
170
+     * sets the verb of the comment, e.g. 'comment' or 'like'
171
+     *
172
+     * @param string $verb
173
+     * @return IComment
174
+     * @since 9.0.0
175
+     */
176
+    public function setVerb($verb);
177 177
 
178
-	/**
179
-	 * returns the actor type
180
-	 *
181
-	 * @return string
182
-	 * @since 9.0.0
183
-	 */
184
-	public function getActorType();
178
+    /**
179
+     * returns the actor type
180
+     *
181
+     * @return string
182
+     * @since 9.0.0
183
+     */
184
+    public function getActorType();
185 185
 
186
-	/**
187
-	 * returns the actor ID
188
-	 *
189
-	 * @return string
190
-	 * @since 9.0.0
191
-	 */
192
-	public function getActorId();
186
+    /**
187
+     * returns the actor ID
188
+     *
189
+     * @return string
190
+     * @since 9.0.0
191
+     */
192
+    public function getActorId();
193 193
 
194
-	/**
195
-	 * sets (overwrites) the actor type and id
196
-	 *
197
-	 * @param string $actorType e.g. 'users'
198
-	 * @param string $actorId e.g. 'zombie234'
199
-	 * @return IComment
200
-	 * @since 9.0.0
201
-	 */
202
-	public function setActor($actorType, $actorId);
194
+    /**
195
+     * sets (overwrites) the actor type and id
196
+     *
197
+     * @param string $actorType e.g. 'users'
198
+     * @param string $actorId e.g. 'zombie234'
199
+     * @return IComment
200
+     * @since 9.0.0
201
+     */
202
+    public function setActor($actorType, $actorId);
203 203
 
204
-	/**
205
-	 * returns the creation date of the comment.
206
-	 *
207
-	 * If not explicitly set, it shall default to the time of initialization.
208
-	 *
209
-	 * @return \DateTime
210
-	 * @since 9.0.0
211
-	 */
212
-	public function getCreationDateTime();
204
+    /**
205
+     * returns the creation date of the comment.
206
+     *
207
+     * If not explicitly set, it shall default to the time of initialization.
208
+     *
209
+     * @return \DateTime
210
+     * @since 9.0.0
211
+     */
212
+    public function getCreationDateTime();
213 213
 
214
-	/**
215
-	 * sets the creation date of the comment and returns itself
216
-	 *
217
-	 * @param \DateTime $dateTime
218
-	 * @return IComment
219
-	 * @since 9.0.0
220
-	 */
221
-	public function setCreationDateTime(\DateTime $dateTime);
214
+    /**
215
+     * sets the creation date of the comment and returns itself
216
+     *
217
+     * @param \DateTime $dateTime
218
+     * @return IComment
219
+     * @since 9.0.0
220
+     */
221
+    public function setCreationDateTime(\DateTime $dateTime);
222 222
 
223
-	/**
224
-	 * returns the date of the most recent child
225
-	 *
226
-	 * @return \DateTime
227
-	 * @since 9.0.0
228
-	 */
229
-	public function getLatestChildDateTime();
223
+    /**
224
+     * returns the date of the most recent child
225
+     *
226
+     * @return \DateTime
227
+     * @since 9.0.0
228
+     */
229
+    public function getLatestChildDateTime();
230 230
 
231
-	/**
232
-	 * sets the date of the most recent child
233
-	 *
234
-	 * @param \DateTime $dateTime
235
-	 * @return IComment
236
-	 * @since 9.0.0
237
-	 */
238
-	public function setLatestChildDateTime(\DateTime $dateTime);
231
+    /**
232
+     * sets the date of the most recent child
233
+     *
234
+     * @param \DateTime $dateTime
235
+     * @return IComment
236
+     * @since 9.0.0
237
+     */
238
+    public function setLatestChildDateTime(\DateTime $dateTime);
239 239
 
240
-	/**
241
-	 * returns the object type the comment is attached to
242
-	 *
243
-	 * @return string
244
-	 * @since 9.0.0
245
-	 */
246
-	public function getObjectType();
240
+    /**
241
+     * returns the object type the comment is attached to
242
+     *
243
+     * @return string
244
+     * @since 9.0.0
245
+     */
246
+    public function getObjectType();
247 247
 
248
-	/**
249
-	 * returns the object id the comment is attached to
250
-	 *
251
-	 * @return string
252
-	 * @since 9.0.0
253
-	 */
254
-	public function getObjectId();
248
+    /**
249
+     * returns the object id the comment is attached to
250
+     *
251
+     * @return string
252
+     * @since 9.0.0
253
+     */
254
+    public function getObjectId();
255 255
 
256
-	/**
257
-	 * sets (overwrites) the object of the comment
258
-	 *
259
-	 * @param string $objectType e.g. 'files'
260
-	 * @param string $objectId e.g. '16435'
261
-	 * @return IComment
262
-	 * @since 9.0.0
263
-	 */
264
-	public function setObject($objectType, $objectId);
256
+    /**
257
+     * sets (overwrites) the object of the comment
258
+     *
259
+     * @param string $objectType e.g. 'files'
260
+     * @param string $objectId e.g. '16435'
261
+     * @return IComment
262
+     * @since 9.0.0
263
+     */
264
+    public function setObject($objectType, $objectId);
265 265
 
266
-	/**
267
-	 * returns the reference id of the comment
268
-	 *
269
-	 * @return string|null
270
-	 * @since 19.0.0
271
-	 */
272
-	public function getReferenceId(): ?string;
266
+    /**
267
+     * returns the reference id of the comment
268
+     *
269
+     * @return string|null
270
+     * @since 19.0.0
271
+     */
272
+    public function getReferenceId(): ?string;
273 273
 
274
-	/**
275
-	 * sets (overwrites) the reference id of the comment
276
-	 *
277
-	 * @param string|null $referenceId e.g. sha256 hash sum
278
-	 * @return IComment
279
-	 * @since 19.0.0
280
-	 */
281
-	public function setReferenceId(?string $referenceId): IComment;
274
+    /**
275
+     * sets (overwrites) the reference id of the comment
276
+     *
277
+     * @param string|null $referenceId e.g. sha256 hash sum
278
+     * @return IComment
279
+     * @since 19.0.0
280
+     */
281
+    public function setReferenceId(?string $referenceId): IComment;
282 282
 
283 283
 }
Please login to merge, or discard this patch.
lib/private/DB/MissingColumnInformation.php 1 patch
Indentation   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -28,16 +28,16 @@
 block discarded – undo
28 28
 
29 29
 class MissingColumnInformation {
30 30
 
31
-	private $listOfMissingColumns = [];
31
+    private $listOfMissingColumns = [];
32 32
 
33
-	public function addHintForMissingColumn(string $tableName, string $columnName): void {
34
-		$this->listOfMissingColumns[] = [
35
-			'tableName' => $tableName,
36
-			'columnName' => $columnName,
37
-		];
38
-	}
33
+    public function addHintForMissingColumn(string $tableName, string $columnName): void {
34
+        $this->listOfMissingColumns[] = [
35
+            'tableName' => $tableName,
36
+            'columnName' => $columnName,
37
+        ];
38
+    }
39 39
 
40
-	public function getListOfMissingColumns(): array {
41
-		return $this->listOfMissingColumns;
42
-	}
40
+    public function getListOfMissingColumns(): array {
41
+        return $this->listOfMissingColumns;
42
+    }
43 43
 }
Please login to merge, or discard this patch.
lib/private/Comments/Comment.php 1 patch
Indentation   +422 added lines, -422 removed lines patch added patch discarded remove patch
@@ -31,426 +31,426 @@
 block discarded – undo
31 31
 
32 32
 class Comment implements IComment {
33 33
 
34
-	protected $data = [
35
-		'id'              => '',
36
-		'parentId'        => '0',
37
-		'topmostParentId' => '0',
38
-		'childrenCount'   => '0',
39
-		'message'         => '',
40
-		'verb'            => '',
41
-		'actorType'       => '',
42
-		'actorId'         => '',
43
-		'objectType'      => '',
44
-		'objectId'        => '',
45
-		'referenceId'     => null,
46
-		'creationDT'      => null,
47
-		'latestChildDT'   => null,
48
-	];
49
-
50
-	/**
51
-	 * Comment constructor.
52
-	 *
53
-	 * @param array $data	optional, array with keys according to column names from
54
-	 * 						the comments database scheme
55
-	 */
56
-	public function __construct(array $data = null) {
57
-		if(is_array($data)) {
58
-			$this->fromArray($data);
59
-		}
60
-	}
61
-
62
-	/**
63
-	 * returns the ID of the comment
64
-	 *
65
-	 * It may return an empty string, if the comment was not stored.
66
-	 * It is expected that the concrete Comment implementation gives an ID
67
-	 * by itself (e.g. after saving).
68
-	 *
69
-	 * @return string
70
-	 * @since 9.0.0
71
-	 */
72
-	public function getId() {
73
-		return $this->data['id'];
74
-	}
75
-
76
-	/**
77
-	 * sets the ID of the comment and returns itself
78
-	 *
79
-	 * It is only allowed to set the ID only, if the current id is an empty
80
-	 * string (which means it is not stored in a database, storage or whatever
81
-	 * the concrete implementation does), or vice versa. Changing a given ID is
82
-	 * not permitted and must result in an IllegalIDChangeException.
83
-	 *
84
-	 * @param string $id
85
-	 * @return IComment
86
-	 * @throws IllegalIDChangeException
87
-	 * @since 9.0.0
88
-	 */
89
-	public function setId($id) {
90
-		if(!is_string($id)) {
91
-			throw new \InvalidArgumentException('String expected.');
92
-		}
93
-
94
-		$id = trim($id);
95
-		if($this->data['id'] === '' || ($this->data['id'] !== '' && $id === '')) {
96
-			$this->data['id'] = $id;
97
-			return $this;
98
-		}
99
-
100
-		throw new IllegalIDChangeException('Not allowed to assign a new ID to an already saved comment.');
101
-	}
102
-
103
-	/**
104
-	 * returns the parent ID of the comment
105
-	 *
106
-	 * @return string
107
-	 * @since 9.0.0
108
-	 */
109
-	public function getParentId() {
110
-		return $this->data['parentId'];
111
-	}
112
-
113
-	/**
114
-	 * sets the parent ID and returns itself
115
-	 *
116
-	 * @param string $parentId
117
-	 * @return IComment
118
-	 * @since 9.0.0
119
-	 */
120
-	public function setParentId($parentId) {
121
-		if(!is_string($parentId)) {
122
-			throw new \InvalidArgumentException('String expected.');
123
-		}
124
-		$this->data['parentId'] = trim($parentId);
125
-		return $this;
126
-	}
127
-
128
-	/**
129
-	 * returns the topmost parent ID of the comment
130
-	 *
131
-	 * @return string
132
-	 * @since 9.0.0
133
-	 */
134
-	public function getTopmostParentId() {
135
-		return $this->data['topmostParentId'];
136
-	}
137
-
138
-
139
-	/**
140
-	 * sets the topmost parent ID and returns itself
141
-	 *
142
-	 * @param string $id
143
-	 * @return IComment
144
-	 * @since 9.0.0
145
-	 */
146
-	public function setTopmostParentId($id) {
147
-		if(!is_string($id)) {
148
-			throw new \InvalidArgumentException('String expected.');
149
-		}
150
-		$this->data['topmostParentId'] = trim($id);
151
-		return $this;
152
-	}
153
-
154
-	/**
155
-	 * returns the number of children
156
-	 *
157
-	 * @return int
158
-	 * @since 9.0.0
159
-	 */
160
-	public function getChildrenCount() {
161
-		return $this->data['childrenCount'];
162
-	}
163
-
164
-	/**
165
-	 * sets the number of children
166
-	 *
167
-	 * @param int $count
168
-	 * @return IComment
169
-	 * @since 9.0.0
170
-	 */
171
-	public function setChildrenCount($count) {
172
-		if(!is_int($count)) {
173
-			throw new \InvalidArgumentException('Integer expected.');
174
-		}
175
-		$this->data['childrenCount'] = $count;
176
-		return $this;
177
-	}
178
-
179
-	/**
180
-	 * returns the message of the comment
181
-	 *
182
-	 * @return string
183
-	 * @since 9.0.0
184
-	 */
185
-	public function getMessage() {
186
-		return $this->data['message'];
187
-	}
188
-
189
-	/**
190
-	 * sets the message of the comment and returns itself
191
-	 *
192
-	 * @param string $message
193
-	 * @param int $maxLength
194
-	 * @return IComment
195
-	 * @throws MessageTooLongException
196
-	 * @since 9.0.0
197
-	 */
198
-	public function setMessage($message, $maxLength = self::MAX_MESSAGE_LENGTH) {
199
-		if(!is_string($message)) {
200
-			throw new \InvalidArgumentException('String expected.');
201
-		}
202
-		$message = trim($message);
203
-		if ($maxLength && mb_strlen($message, 'UTF-8') > $maxLength) {
204
-			throw new MessageTooLongException('Comment message must not exceed ' . $maxLength. ' characters');
205
-		}
206
-		$this->data['message'] = $message;
207
-		return $this;
208
-	}
209
-
210
-	/**
211
-	 * returns an array containing mentions that are included in the comment
212
-	 *
213
-	 * @return array each mention provides a 'type' and an 'id', see example below
214
-	 * @since 11.0.0
215
-	 *
216
-	 * The return array looks like:
217
-	 * [
218
-	 *   [
219
-	 *     'type' => 'user',
220
-	 *     'id' => 'citizen4'
221
-	 *   ],
222
-	 *   [
223
-	 *     'type' => 'group',
224
-	 *     'id' => 'media'
225
-	 *   ],
226
-	 *   …
227
-	 * ]
228
-	 *
229
-	 */
230
-	public function getMentions() {
231
-		$ok = preg_match_all("/\B(?<![^a-z0-9_\-@\.\'\s])@(\"guest\/[a-f0-9]+\"|\"[a-z0-9_\-@\.\' ]+\"|[a-z0-9_\-@\.\']+)/i", $this->getMessage(), $mentions);
232
-		if(!$ok || !isset($mentions[0]) || !is_array($mentions[0])) {
233
-			return [];
234
-		}
235
-		$uids = array_unique($mentions[0]);
236
-		$result = [];
237
-		foreach ($uids as $uid) {
238
-			$cleanUid = trim(substr($uid, 1), '"');
239
-			if (strpos($cleanUid, 'guest/') === 0) {
240
-				$result[] = ['type' => 'guest', 'id' => $cleanUid];
241
-			} else {
242
-				$result[] = ['type' => 'user', 'id' => $cleanUid];
243
-			}
244
-		}
245
-		return $result;
246
-	}
247
-
248
-	/**
249
-	 * returns the verb of the comment
250
-	 *
251
-	 * @return string
252
-	 * @since 9.0.0
253
-	 */
254
-	public function getVerb() {
255
-		return $this->data['verb'];
256
-	}
257
-
258
-	/**
259
-	 * sets the verb of the comment, e.g. 'comment' or 'like'
260
-	 *
261
-	 * @param string $verb
262
-	 * @return IComment
263
-	 * @since 9.0.0
264
-	 */
265
-	public function setVerb($verb) {
266
-		if(!is_string($verb) || !trim($verb)) {
267
-			throw new \InvalidArgumentException('Non-empty String expected.');
268
-		}
269
-		$this->data['verb'] = trim($verb);
270
-		return $this;
271
-	}
272
-
273
-	/**
274
-	 * returns the actor type
275
-	 *
276
-	 * @return string
277
-	 * @since 9.0.0
278
-	 */
279
-	public function getActorType() {
280
-		return $this->data['actorType'];
281
-	}
282
-
283
-	/**
284
-	 * returns the actor ID
285
-	 *
286
-	 * @return string
287
-	 * @since 9.0.0
288
-	 */
289
-	public function getActorId() {
290
-		return $this->data['actorId'];
291
-	}
292
-
293
-	/**
294
-	 * sets (overwrites) the actor type and id
295
-	 *
296
-	 * @param string $actorType e.g. 'users'
297
-	 * @param string $actorId e.g. 'zombie234'
298
-	 * @return IComment
299
-	 * @since 9.0.0
300
-	 */
301
-	public function setActor($actorType, $actorId) {
302
-		if(
303
-		       !is_string($actorType) || !trim($actorType)
304
-		    || !is_string($actorId)   || $actorId === ''
305
-		) {
306
-			throw new \InvalidArgumentException('String expected.');
307
-		}
308
-		$this->data['actorType'] = trim($actorType);
309
-		$this->data['actorId']   = $actorId;
310
-		return $this;
311
-	}
312
-
313
-	/**
314
-	 * returns the creation date of the comment.
315
-	 *
316
-	 * If not explicitly set, it shall default to the time of initialization.
317
-	 *
318
-	 * @return \DateTime
319
-	 * @since 9.0.0
320
-	 */
321
-	public function getCreationDateTime() {
322
-		return $this->data['creationDT'];
323
-	}
324
-
325
-	/**
326
-	 * sets the creation date of the comment and returns itself
327
-	 *
328
-	 * @param \DateTime $timestamp
329
-	 * @return IComment
330
-	 * @since 9.0.0
331
-	 */
332
-	public function setCreationDateTime(\DateTime $timestamp) {
333
-		$this->data['creationDT'] = $timestamp;
334
-		return $this;
335
-	}
336
-
337
-	/**
338
-	 * returns the DateTime of the most recent child, if set, otherwise null
339
-	 *
340
-	 * @return \DateTime|null
341
-	 * @since 9.0.0
342
-	 */
343
-	public function getLatestChildDateTime() {
344
-		return $this->data['latestChildDT'];
345
-	}
346
-
347
-	/**
348
-	 * sets the date of the most recent child
349
-	 *
350
-	 * @param \DateTime $dateTime
351
-	 * @return IComment
352
-	 * @since 9.0.0
353
-	 */
354
-	public function setLatestChildDateTime(\DateTime $dateTime = null) {
355
-		$this->data['latestChildDT'] = $dateTime;
356
-		return $this;
357
-	}
358
-
359
-	/**
360
-	 * returns the object type the comment is attached to
361
-	 *
362
-	 * @return string
363
-	 * @since 9.0.0
364
-	 */
365
-	public function getObjectType() {
366
-		return $this->data['objectType'];
367
-	}
368
-
369
-	/**
370
-	 * returns the object id the comment is attached to
371
-	 *
372
-	 * @return string
373
-	 * @since 9.0.0
374
-	 */
375
-	public function getObjectId() {
376
-		return $this->data['objectId'];
377
-	}
378
-
379
-	/**
380
-	 * sets (overwrites) the object of the comment
381
-	 *
382
-	 * @param string $objectType e.g. 'files'
383
-	 * @param string $objectId e.g. '16435'
384
-	 * @return IComment
385
-	 * @since 9.0.0
386
-	 */
387
-	public function setObject($objectType, $objectId) {
388
-		if(
389
-		       !is_string($objectType) || !trim($objectType)
390
-		    || !is_string($objectId)   || trim($objectId) === ''
391
-		) {
392
-			throw new \InvalidArgumentException('String expected.');
393
-		}
394
-		$this->data['objectType'] = trim($objectType);
395
-		$this->data['objectId']   = trim($objectId);
396
-		return $this;
397
-	}
398
-
399
-	/**
400
-	 * returns the reference id of the comment
401
-	 *
402
-	 * @return string|null
403
-	 * @since 19.0.0
404
-	 */
405
-	public function getReferenceId(): ?string {
406
-		return $this->data['referenceId'];
407
-	}
408
-
409
-	/**
410
-	 * sets (overwrites) the reference id of the comment
411
-	 *
412
-	 * @param string $referenceId e.g. sha256 hash sum
413
-	 * @return IComment
414
-	 * @since 19.0.0
415
-	 */
416
-	public function setReferenceId(?string $referenceId): IComment {
417
-		if ($referenceId === null) {
418
-			$this->data['referenceId'] = $referenceId;
419
-		} else {
420
-			$referenceId = trim($referenceId);
421
-			if ($referenceId === '') {
422
-				throw new \InvalidArgumentException('Non empty string expected.');
423
-			}
424
-			$this->data['referenceId'] = $referenceId;
425
-		}
426
-		return $this;
427
-	}
428
-
429
-	/**
430
-	 * sets the comment data based on an array with keys as taken from the
431
-	 * database.
432
-	 *
433
-	 * @param array $data
434
-	 * @return IComment
435
-	 */
436
-	protected function fromArray($data) {
437
-		foreach(array_keys($data) as $key) {
438
-			// translate DB keys to internal setter names
439
-			$setter = 'set' . implode('', array_map('ucfirst', explode('_', $key)));
440
-			$setter = str_replace('Timestamp', 'DateTime', $setter);
441
-
442
-			if(method_exists($this, $setter)) {
443
-				$this->$setter($data[$key]);
444
-			}
445
-		}
446
-
447
-		foreach(['actor', 'object'] as $role) {
448
-			if(isset($data[$role . '_type']) && isset($data[$role . '_id'])) {
449
-				$setter = 'set' . ucfirst($role);
450
-				$this->$setter($data[$role . '_type'], $data[$role . '_id']);
451
-			}
452
-		}
453
-
454
-		return $this;
455
-	}
34
+    protected $data = [
35
+        'id'              => '',
36
+        'parentId'        => '0',
37
+        'topmostParentId' => '0',
38
+        'childrenCount'   => '0',
39
+        'message'         => '',
40
+        'verb'            => '',
41
+        'actorType'       => '',
42
+        'actorId'         => '',
43
+        'objectType'      => '',
44
+        'objectId'        => '',
45
+        'referenceId'     => null,
46
+        'creationDT'      => null,
47
+        'latestChildDT'   => null,
48
+    ];
49
+
50
+    /**
51
+     * Comment constructor.
52
+     *
53
+     * @param array $data	optional, array with keys according to column names from
54
+     * 						the comments database scheme
55
+     */
56
+    public function __construct(array $data = null) {
57
+        if(is_array($data)) {
58
+            $this->fromArray($data);
59
+        }
60
+    }
61
+
62
+    /**
63
+     * returns the ID of the comment
64
+     *
65
+     * It may return an empty string, if the comment was not stored.
66
+     * It is expected that the concrete Comment implementation gives an ID
67
+     * by itself (e.g. after saving).
68
+     *
69
+     * @return string
70
+     * @since 9.0.0
71
+     */
72
+    public function getId() {
73
+        return $this->data['id'];
74
+    }
75
+
76
+    /**
77
+     * sets the ID of the comment and returns itself
78
+     *
79
+     * It is only allowed to set the ID only, if the current id is an empty
80
+     * string (which means it is not stored in a database, storage or whatever
81
+     * the concrete implementation does), or vice versa. Changing a given ID is
82
+     * not permitted and must result in an IllegalIDChangeException.
83
+     *
84
+     * @param string $id
85
+     * @return IComment
86
+     * @throws IllegalIDChangeException
87
+     * @since 9.0.0
88
+     */
89
+    public function setId($id) {
90
+        if(!is_string($id)) {
91
+            throw new \InvalidArgumentException('String expected.');
92
+        }
93
+
94
+        $id = trim($id);
95
+        if($this->data['id'] === '' || ($this->data['id'] !== '' && $id === '')) {
96
+            $this->data['id'] = $id;
97
+            return $this;
98
+        }
99
+
100
+        throw new IllegalIDChangeException('Not allowed to assign a new ID to an already saved comment.');
101
+    }
102
+
103
+    /**
104
+     * returns the parent ID of the comment
105
+     *
106
+     * @return string
107
+     * @since 9.0.0
108
+     */
109
+    public function getParentId() {
110
+        return $this->data['parentId'];
111
+    }
112
+
113
+    /**
114
+     * sets the parent ID and returns itself
115
+     *
116
+     * @param string $parentId
117
+     * @return IComment
118
+     * @since 9.0.0
119
+     */
120
+    public function setParentId($parentId) {
121
+        if(!is_string($parentId)) {
122
+            throw new \InvalidArgumentException('String expected.');
123
+        }
124
+        $this->data['parentId'] = trim($parentId);
125
+        return $this;
126
+    }
127
+
128
+    /**
129
+     * returns the topmost parent ID of the comment
130
+     *
131
+     * @return string
132
+     * @since 9.0.0
133
+     */
134
+    public function getTopmostParentId() {
135
+        return $this->data['topmostParentId'];
136
+    }
137
+
138
+
139
+    /**
140
+     * sets the topmost parent ID and returns itself
141
+     *
142
+     * @param string $id
143
+     * @return IComment
144
+     * @since 9.0.0
145
+     */
146
+    public function setTopmostParentId($id) {
147
+        if(!is_string($id)) {
148
+            throw new \InvalidArgumentException('String expected.');
149
+        }
150
+        $this->data['topmostParentId'] = trim($id);
151
+        return $this;
152
+    }
153
+
154
+    /**
155
+     * returns the number of children
156
+     *
157
+     * @return int
158
+     * @since 9.0.0
159
+     */
160
+    public function getChildrenCount() {
161
+        return $this->data['childrenCount'];
162
+    }
163
+
164
+    /**
165
+     * sets the number of children
166
+     *
167
+     * @param int $count
168
+     * @return IComment
169
+     * @since 9.0.0
170
+     */
171
+    public function setChildrenCount($count) {
172
+        if(!is_int($count)) {
173
+            throw new \InvalidArgumentException('Integer expected.');
174
+        }
175
+        $this->data['childrenCount'] = $count;
176
+        return $this;
177
+    }
178
+
179
+    /**
180
+     * returns the message of the comment
181
+     *
182
+     * @return string
183
+     * @since 9.0.0
184
+     */
185
+    public function getMessage() {
186
+        return $this->data['message'];
187
+    }
188
+
189
+    /**
190
+     * sets the message of the comment and returns itself
191
+     *
192
+     * @param string $message
193
+     * @param int $maxLength
194
+     * @return IComment
195
+     * @throws MessageTooLongException
196
+     * @since 9.0.0
197
+     */
198
+    public function setMessage($message, $maxLength = self::MAX_MESSAGE_LENGTH) {
199
+        if(!is_string($message)) {
200
+            throw new \InvalidArgumentException('String expected.');
201
+        }
202
+        $message = trim($message);
203
+        if ($maxLength && mb_strlen($message, 'UTF-8') > $maxLength) {
204
+            throw new MessageTooLongException('Comment message must not exceed ' . $maxLength. ' characters');
205
+        }
206
+        $this->data['message'] = $message;
207
+        return $this;
208
+    }
209
+
210
+    /**
211
+     * returns an array containing mentions that are included in the comment
212
+     *
213
+     * @return array each mention provides a 'type' and an 'id', see example below
214
+     * @since 11.0.0
215
+     *
216
+     * The return array looks like:
217
+     * [
218
+     *   [
219
+     *     'type' => 'user',
220
+     *     'id' => 'citizen4'
221
+     *   ],
222
+     *   [
223
+     *     'type' => 'group',
224
+     *     'id' => 'media'
225
+     *   ],
226
+     *   …
227
+     * ]
228
+     *
229
+     */
230
+    public function getMentions() {
231
+        $ok = preg_match_all("/\B(?<![^a-z0-9_\-@\.\'\s])@(\"guest\/[a-f0-9]+\"|\"[a-z0-9_\-@\.\' ]+\"|[a-z0-9_\-@\.\']+)/i", $this->getMessage(), $mentions);
232
+        if(!$ok || !isset($mentions[0]) || !is_array($mentions[0])) {
233
+            return [];
234
+        }
235
+        $uids = array_unique($mentions[0]);
236
+        $result = [];
237
+        foreach ($uids as $uid) {
238
+            $cleanUid = trim(substr($uid, 1), '"');
239
+            if (strpos($cleanUid, 'guest/') === 0) {
240
+                $result[] = ['type' => 'guest', 'id' => $cleanUid];
241
+            } else {
242
+                $result[] = ['type' => 'user', 'id' => $cleanUid];
243
+            }
244
+        }
245
+        return $result;
246
+    }
247
+
248
+    /**
249
+     * returns the verb of the comment
250
+     *
251
+     * @return string
252
+     * @since 9.0.0
253
+     */
254
+    public function getVerb() {
255
+        return $this->data['verb'];
256
+    }
257
+
258
+    /**
259
+     * sets the verb of the comment, e.g. 'comment' or 'like'
260
+     *
261
+     * @param string $verb
262
+     * @return IComment
263
+     * @since 9.0.0
264
+     */
265
+    public function setVerb($verb) {
266
+        if(!is_string($verb) || !trim($verb)) {
267
+            throw new \InvalidArgumentException('Non-empty String expected.');
268
+        }
269
+        $this->data['verb'] = trim($verb);
270
+        return $this;
271
+    }
272
+
273
+    /**
274
+     * returns the actor type
275
+     *
276
+     * @return string
277
+     * @since 9.0.0
278
+     */
279
+    public function getActorType() {
280
+        return $this->data['actorType'];
281
+    }
282
+
283
+    /**
284
+     * returns the actor ID
285
+     *
286
+     * @return string
287
+     * @since 9.0.0
288
+     */
289
+    public function getActorId() {
290
+        return $this->data['actorId'];
291
+    }
292
+
293
+    /**
294
+     * sets (overwrites) the actor type and id
295
+     *
296
+     * @param string $actorType e.g. 'users'
297
+     * @param string $actorId e.g. 'zombie234'
298
+     * @return IComment
299
+     * @since 9.0.0
300
+     */
301
+    public function setActor($actorType, $actorId) {
302
+        if(
303
+                !is_string($actorType) || !trim($actorType)
304
+            || !is_string($actorId)   || $actorId === ''
305
+        ) {
306
+            throw new \InvalidArgumentException('String expected.');
307
+        }
308
+        $this->data['actorType'] = trim($actorType);
309
+        $this->data['actorId']   = $actorId;
310
+        return $this;
311
+    }
312
+
313
+    /**
314
+     * returns the creation date of the comment.
315
+     *
316
+     * If not explicitly set, it shall default to the time of initialization.
317
+     *
318
+     * @return \DateTime
319
+     * @since 9.0.0
320
+     */
321
+    public function getCreationDateTime() {
322
+        return $this->data['creationDT'];
323
+    }
324
+
325
+    /**
326
+     * sets the creation date of the comment and returns itself
327
+     *
328
+     * @param \DateTime $timestamp
329
+     * @return IComment
330
+     * @since 9.0.0
331
+     */
332
+    public function setCreationDateTime(\DateTime $timestamp) {
333
+        $this->data['creationDT'] = $timestamp;
334
+        return $this;
335
+    }
336
+
337
+    /**
338
+     * returns the DateTime of the most recent child, if set, otherwise null
339
+     *
340
+     * @return \DateTime|null
341
+     * @since 9.0.0
342
+     */
343
+    public function getLatestChildDateTime() {
344
+        return $this->data['latestChildDT'];
345
+    }
346
+
347
+    /**
348
+     * sets the date of the most recent child
349
+     *
350
+     * @param \DateTime $dateTime
351
+     * @return IComment
352
+     * @since 9.0.0
353
+     */
354
+    public function setLatestChildDateTime(\DateTime $dateTime = null) {
355
+        $this->data['latestChildDT'] = $dateTime;
356
+        return $this;
357
+    }
358
+
359
+    /**
360
+     * returns the object type the comment is attached to
361
+     *
362
+     * @return string
363
+     * @since 9.0.0
364
+     */
365
+    public function getObjectType() {
366
+        return $this->data['objectType'];
367
+    }
368
+
369
+    /**
370
+     * returns the object id the comment is attached to
371
+     *
372
+     * @return string
373
+     * @since 9.0.0
374
+     */
375
+    public function getObjectId() {
376
+        return $this->data['objectId'];
377
+    }
378
+
379
+    /**
380
+     * sets (overwrites) the object of the comment
381
+     *
382
+     * @param string $objectType e.g. 'files'
383
+     * @param string $objectId e.g. '16435'
384
+     * @return IComment
385
+     * @since 9.0.0
386
+     */
387
+    public function setObject($objectType, $objectId) {
388
+        if(
389
+                !is_string($objectType) || !trim($objectType)
390
+            || !is_string($objectId)   || trim($objectId) === ''
391
+        ) {
392
+            throw new \InvalidArgumentException('String expected.');
393
+        }
394
+        $this->data['objectType'] = trim($objectType);
395
+        $this->data['objectId']   = trim($objectId);
396
+        return $this;
397
+    }
398
+
399
+    /**
400
+     * returns the reference id of the comment
401
+     *
402
+     * @return string|null
403
+     * @since 19.0.0
404
+     */
405
+    public function getReferenceId(): ?string {
406
+        return $this->data['referenceId'];
407
+    }
408
+
409
+    /**
410
+     * sets (overwrites) the reference id of the comment
411
+     *
412
+     * @param string $referenceId e.g. sha256 hash sum
413
+     * @return IComment
414
+     * @since 19.0.0
415
+     */
416
+    public function setReferenceId(?string $referenceId): IComment {
417
+        if ($referenceId === null) {
418
+            $this->data['referenceId'] = $referenceId;
419
+        } else {
420
+            $referenceId = trim($referenceId);
421
+            if ($referenceId === '') {
422
+                throw new \InvalidArgumentException('Non empty string expected.');
423
+            }
424
+            $this->data['referenceId'] = $referenceId;
425
+        }
426
+        return $this;
427
+    }
428
+
429
+    /**
430
+     * sets the comment data based on an array with keys as taken from the
431
+     * database.
432
+     *
433
+     * @param array $data
434
+     * @return IComment
435
+     */
436
+    protected function fromArray($data) {
437
+        foreach(array_keys($data) as $key) {
438
+            // translate DB keys to internal setter names
439
+            $setter = 'set' . implode('', array_map('ucfirst', explode('_', $key)));
440
+            $setter = str_replace('Timestamp', 'DateTime', $setter);
441
+
442
+            if(method_exists($this, $setter)) {
443
+                $this->$setter($data[$key]);
444
+            }
445
+        }
446
+
447
+        foreach(['actor', 'object'] as $role) {
448
+            if(isset($data[$role . '_type']) && isset($data[$role . '_id'])) {
449
+                $setter = 'set' . ucfirst($role);
450
+                $this->$setter($data[$role . '_type'], $data[$role . '_id']);
451
+            }
452
+        }
453
+
454
+        return $this;
455
+    }
456 456
 }
Please login to merge, or discard this patch.
lib/private/Comments/Manager.php 1 patch
Indentation   +1079 added lines, -1079 removed lines patch added patch discarded remove patch
@@ -43,1083 +43,1083 @@
 block discarded – undo
43 43
 
44 44
 class Manager implements ICommentsManager {
45 45
 
46
-	/** @var  IDBConnection */
47
-	protected $dbConn;
48
-
49
-	/** @var  ILogger */
50
-	protected $logger;
51
-
52
-	/** @var IConfig */
53
-	protected $config;
54
-
55
-	/** @var IComment[] */
56
-	protected $commentsCache = [];
57
-
58
-	/** @var  \Closure[] */
59
-	protected $eventHandlerClosures = [];
60
-
61
-	/** @var  ICommentsEventHandler[] */
62
-	protected $eventHandlers = [];
63
-
64
-	/** @var \Closure[] */
65
-	protected $displayNameResolvers = [];
66
-
67
-	/**
68
-	 * Manager constructor.
69
-	 *
70
-	 * @param IDBConnection $dbConn
71
-	 * @param ILogger $logger
72
-	 * @param IConfig $config
73
-	 */
74
-	public function __construct(
75
-		IDBConnection $dbConn,
76
-		ILogger $logger,
77
-		IConfig $config
78
-	) {
79
-		$this->dbConn = $dbConn;
80
-		$this->logger = $logger;
81
-		$this->config = $config;
82
-	}
83
-
84
-	/**
85
-	 * converts data base data into PHP native, proper types as defined by
86
-	 * IComment interface.
87
-	 *
88
-	 * @param array $data
89
-	 * @return array
90
-	 */
91
-	protected function normalizeDatabaseData(array $data) {
92
-		$data['id'] = (string)$data['id'];
93
-		$data['parent_id'] = (string)$data['parent_id'];
94
-		$data['topmost_parent_id'] = (string)$data['topmost_parent_id'];
95
-		$data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
96
-		if (!is_null($data['latest_child_timestamp'])) {
97
-			$data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
98
-		}
99
-		$data['children_count'] = (int)$data['children_count'];
100
-		$data['reference_id'] = $data['reference_id'] ?? null;
101
-		return $data;
102
-	}
103
-
104
-
105
-	/**
106
-	 * @param array $data
107
-	 * @return IComment
108
-	 */
109
-	public function getCommentFromData(array $data): IComment {
110
-		return new Comment($this->normalizeDatabaseData($data));
111
-	}
112
-
113
-	/**
114
-	 * prepares a comment for an insert or update operation after making sure
115
-	 * all necessary fields have a value assigned.
116
-	 *
117
-	 * @param IComment $comment
118
-	 * @return IComment returns the same updated IComment instance as provided
119
-	 *                  by parameter for convenience
120
-	 * @throws \UnexpectedValueException
121
-	 */
122
-	protected function prepareCommentForDatabaseWrite(IComment $comment) {
123
-		if (!$comment->getActorType()
124
-			|| $comment->getActorId() === ''
125
-			|| !$comment->getObjectType()
126
-			|| $comment->getObjectId() === ''
127
-			|| !$comment->getVerb()
128
-		) {
129
-			throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
130
-		}
131
-
132
-		if ($comment->getId() === '') {
133
-			$comment->setChildrenCount(0);
134
-			$comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
135
-			$comment->setLatestChildDateTime(null);
136
-		}
137
-
138
-		if (is_null($comment->getCreationDateTime())) {
139
-			$comment->setCreationDateTime(new \DateTime());
140
-		}
141
-
142
-		if ($comment->getParentId() !== '0') {
143
-			$comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
144
-		} else {
145
-			$comment->setTopmostParentId('0');
146
-		}
147
-
148
-		$this->cache($comment);
149
-
150
-		return $comment;
151
-	}
152
-
153
-	/**
154
-	 * returns the topmost parent id of a given comment identified by ID
155
-	 *
156
-	 * @param string $id
157
-	 * @return string
158
-	 * @throws NotFoundException
159
-	 */
160
-	protected function determineTopmostParentId($id) {
161
-		$comment = $this->get($id);
162
-		if ($comment->getParentId() === '0') {
163
-			return $comment->getId();
164
-		}
165
-
166
-		return $this->determineTopmostParentId($comment->getParentId());
167
-	}
168
-
169
-	/**
170
-	 * updates child information of a comment
171
-	 *
172
-	 * @param string $id
173
-	 * @param \DateTime $cDateTime the date time of the most recent child
174
-	 * @throws NotFoundException
175
-	 */
176
-	protected function updateChildrenInformation($id, \DateTime $cDateTime) {
177
-		$qb = $this->dbConn->getQueryBuilder();
178
-		$query = $qb->select($qb->func()->count('id'))
179
-			->from('comments')
180
-			->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
181
-			->setParameter('id', $id);
182
-
183
-		$resultStatement = $query->execute();
184
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
185
-		$resultStatement->closeCursor();
186
-		$children = (int)$data[0];
187
-
188
-		$comment = $this->get($id);
189
-		$comment->setChildrenCount($children);
190
-		$comment->setLatestChildDateTime($cDateTime);
191
-		$this->save($comment);
192
-	}
193
-
194
-	/**
195
-	 * Tests whether actor or object type and id parameters are acceptable.
196
-	 * Throws exception if not.
197
-	 *
198
-	 * @param string $role
199
-	 * @param string $type
200
-	 * @param string $id
201
-	 * @throws \InvalidArgumentException
202
-	 */
203
-	protected function checkRoleParameters($role, $type, $id) {
204
-		if (
205
-			!is_string($type) || empty($type)
206
-			|| !is_string($id) || empty($id)
207
-		) {
208
-			throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
209
-		}
210
-	}
211
-
212
-	/**
213
-	 * run-time caches a comment
214
-	 *
215
-	 * @param IComment $comment
216
-	 */
217
-	protected function cache(IComment $comment) {
218
-		$id = $comment->getId();
219
-		if (empty($id)) {
220
-			return;
221
-		}
222
-		$this->commentsCache[(string)$id] = $comment;
223
-	}
224
-
225
-	/**
226
-	 * removes an entry from the comments run time cache
227
-	 *
228
-	 * @param mixed $id the comment's id
229
-	 */
230
-	protected function uncache($id) {
231
-		$id = (string)$id;
232
-		if (isset($this->commentsCache[$id])) {
233
-			unset($this->commentsCache[$id]);
234
-		}
235
-	}
236
-
237
-	/**
238
-	 * returns a comment instance
239
-	 *
240
-	 * @param string $id the ID of the comment
241
-	 * @return IComment
242
-	 * @throws NotFoundException
243
-	 * @throws \InvalidArgumentException
244
-	 * @since 9.0.0
245
-	 */
246
-	public function get($id) {
247
-		if ((int)$id === 0) {
248
-			throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
249
-		}
250
-
251
-		if (isset($this->commentsCache[$id])) {
252
-			return $this->commentsCache[$id];
253
-		}
254
-
255
-		$qb = $this->dbConn->getQueryBuilder();
256
-		$resultStatement = $qb->select('*')
257
-			->from('comments')
258
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
259
-			->setParameter('id', $id, IQueryBuilder::PARAM_INT)
260
-			->execute();
261
-
262
-		$data = $resultStatement->fetch();
263
-		$resultStatement->closeCursor();
264
-		if (!$data) {
265
-			throw new NotFoundException();
266
-		}
267
-
268
-
269
-		$comment = $this->getCommentFromData($data);
270
-		$this->cache($comment);
271
-		return $comment;
272
-	}
273
-
274
-	/**
275
-	 * returns the comment specified by the id and all it's child comments.
276
-	 * At this point of time, we do only support one level depth.
277
-	 *
278
-	 * @param string $id
279
-	 * @param int $limit max number of entries to return, 0 returns all
280
-	 * @param int $offset the start entry
281
-	 * @return array
282
-	 * @since 9.0.0
283
-	 *
284
-	 * The return array looks like this
285
-	 * [
286
-	 *   'comment' => IComment, // root comment
287
-	 *   'replies' =>
288
-	 *   [
289
-	 *     0 =>
290
-	 *     [
291
-	 *       'comment' => IComment,
292
-	 *       'replies' => []
293
-	 *     ]
294
-	 *     1 =>
295
-	 *     [
296
-	 *       'comment' => IComment,
297
-	 *       'replies'=> []
298
-	 *     ],
299
-	 *     …
300
-	 *   ]
301
-	 * ]
302
-	 */
303
-	public function getTree($id, $limit = 0, $offset = 0) {
304
-		$tree = [];
305
-		$tree['comment'] = $this->get($id);
306
-		$tree['replies'] = [];
307
-
308
-		$qb = $this->dbConn->getQueryBuilder();
309
-		$query = $qb->select('*')
310
-			->from('comments')
311
-			->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
312
-			->orderBy('creation_timestamp', 'DESC')
313
-			->setParameter('id', $id);
314
-
315
-		if ($limit > 0) {
316
-			$query->setMaxResults($limit);
317
-		}
318
-		if ($offset > 0) {
319
-			$query->setFirstResult($offset);
320
-		}
321
-
322
-		$resultStatement = $query->execute();
323
-		while ($data = $resultStatement->fetch()) {
324
-			$comment = $this->getCommentFromData($data);
325
-			$this->cache($comment);
326
-			$tree['replies'][] = [
327
-				'comment' => $comment,
328
-				'replies' => []
329
-			];
330
-		}
331
-		$resultStatement->closeCursor();
332
-
333
-		return $tree;
334
-	}
335
-
336
-	/**
337
-	 * returns comments for a specific object (e.g. a file).
338
-	 *
339
-	 * The sort order is always newest to oldest.
340
-	 *
341
-	 * @param string $objectType the object type, e.g. 'files'
342
-	 * @param string $objectId the id of the object
343
-	 * @param int $limit optional, number of maximum comments to be returned. if
344
-	 * not specified, all comments are returned.
345
-	 * @param int $offset optional, starting point
346
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
347
-	 * that may be returned
348
-	 * @return IComment[]
349
-	 * @since 9.0.0
350
-	 */
351
-	public function getForObject(
352
-		$objectType,
353
-		$objectId,
354
-		$limit = 0,
355
-		$offset = 0,
356
-		\DateTime $notOlderThan = null
357
-	) {
358
-		$comments = [];
359
-
360
-		$qb = $this->dbConn->getQueryBuilder();
361
-		$query = $qb->select('*')
362
-			->from('comments')
363
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
364
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
365
-			->orderBy('creation_timestamp', 'DESC')
366
-			->setParameter('type', $objectType)
367
-			->setParameter('id', $objectId);
368
-
369
-		if ($limit > 0) {
370
-			$query->setMaxResults($limit);
371
-		}
372
-		if ($offset > 0) {
373
-			$query->setFirstResult($offset);
374
-		}
375
-		if (!is_null($notOlderThan)) {
376
-			$query
377
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
378
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
379
-		}
380
-
381
-		$resultStatement = $query->execute();
382
-		while ($data = $resultStatement->fetch()) {
383
-			$comment = $this->getCommentFromData($data);
384
-			$this->cache($comment);
385
-			$comments[] = $comment;
386
-		}
387
-		$resultStatement->closeCursor();
388
-
389
-		return $comments;
390
-	}
391
-
392
-	/**
393
-	 * @param string $objectType the object type, e.g. 'files'
394
-	 * @param string $objectId the id of the object
395
-	 * @param int $lastKnownCommentId the last known comment (will be used as offset)
396
-	 * @param string $sortDirection direction of the comments (`asc` or `desc`)
397
-	 * @param int $limit optional, number of maximum comments to be returned. if
398
-	 * set to 0, all comments are returned.
399
-	 * @return IComment[]
400
-	 * @return array
401
-	 */
402
-	public function getForObjectSince(
403
-		string $objectType,
404
-		string $objectId,
405
-		int $lastKnownCommentId,
406
-		string $sortDirection = 'asc',
407
-		int $limit = 30
408
-	): array {
409
-		$comments = [];
410
-
411
-		$query = $this->dbConn->getQueryBuilder();
412
-		$query->select('*')
413
-			->from('comments')
414
-			->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
415
-			->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
416
-			->orderBy('creation_timestamp', $sortDirection === 'desc' ? 'DESC' : 'ASC')
417
-			->addOrderBy('id', $sortDirection === 'desc' ? 'DESC' : 'ASC');
418
-
419
-		if ($limit > 0) {
420
-			$query->setMaxResults($limit);
421
-		}
422
-
423
-		$lastKnownComment = $lastKnownCommentId > 0 ? $this->getLastKnownComment(
424
-			$objectType,
425
-			$objectId,
426
-			$lastKnownCommentId
427
-		) : null;
428
-		if ($lastKnownComment instanceof IComment) {
429
-			$lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
430
-			if ($sortDirection === 'desc') {
431
-				$query->andWhere(
432
-					$query->expr()->orX(
433
-						$query->expr()->lt(
434
-							'creation_timestamp',
435
-							$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
436
-							IQueryBuilder::PARAM_DATE
437
-						),
438
-						$query->expr()->andX(
439
-							$query->expr()->eq(
440
-								'creation_timestamp',
441
-								$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
442
-								IQueryBuilder::PARAM_DATE
443
-							),
444
-							$query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
445
-						)
446
-					)
447
-				);
448
-			} else {
449
-				$query->andWhere(
450
-					$query->expr()->orX(
451
-						$query->expr()->gt(
452
-							'creation_timestamp',
453
-							$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
454
-							IQueryBuilder::PARAM_DATE
455
-						),
456
-						$query->expr()->andX(
457
-							$query->expr()->eq(
458
-								'creation_timestamp',
459
-								$query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
460
-								IQueryBuilder::PARAM_DATE
461
-							),
462
-							$query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
463
-						)
464
-					)
465
-				);
466
-			}
467
-		}
468
-
469
-		$resultStatement = $query->execute();
470
-		while ($data = $resultStatement->fetch()) {
471
-			$comment = $this->getCommentFromData($data);
472
-			$this->cache($comment);
473
-			$comments[] = $comment;
474
-		}
475
-		$resultStatement->closeCursor();
476
-
477
-		return $comments;
478
-	}
479
-
480
-	/**
481
-	 * @param string $objectType the object type, e.g. 'files'
482
-	 * @param string $objectId the id of the object
483
-	 * @param int $id the comment to look for
484
-	 * @return Comment|null
485
-	 */
486
-	protected function getLastKnownComment(string $objectType,
487
-										   string $objectId,
488
-										   int $id) {
489
-		$query = $this->dbConn->getQueryBuilder();
490
-		$query->select('*')
491
-			->from('comments')
492
-			->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
493
-			->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
494
-			->andWhere($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
495
-
496
-		$result = $query->execute();
497
-		$row = $result->fetch();
498
-		$result->closeCursor();
499
-
500
-		if ($row) {
501
-			$comment = $this->getCommentFromData($row);
502
-			$this->cache($comment);
503
-			return $comment;
504
-		}
505
-
506
-		return null;
507
-	}
508
-
509
-	/**
510
-	 * Search for comments with a given content
511
-	 *
512
-	 * @param string $search content to search for
513
-	 * @param string $objectType Limit the search by object type
514
-	 * @param string $objectId Limit the search by object id
515
-	 * @param string $verb Limit the verb of the comment
516
-	 * @param int $offset
517
-	 * @param int $limit
518
-	 * @return IComment[]
519
-	 */
520
-	public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
521
-		$query = $this->dbConn->getQueryBuilder();
522
-
523
-		$query->select('*')
524
-			->from('comments')
525
-			->where($query->expr()->iLike('message', $query->createNamedParameter(
526
-				'%' . $this->dbConn->escapeLikeParameter($search). '%'
527
-			)))
528
-			->orderBy('creation_timestamp', 'DESC')
529
-			->addOrderBy('id', 'DESC')
530
-			->setMaxResults($limit);
531
-
532
-		if ($objectType !== '') {
533
-			$query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
534
-		}
535
-		if ($objectId !== '') {
536
-			$query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
537
-		}
538
-		if ($verb !== '') {
539
-			$query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
540
-		}
541
-		if ($offset !== 0) {
542
-			$query->setFirstResult($offset);
543
-		}
544
-
545
-		$comments = [];
546
-		$result = $query->execute();
547
-		while ($data = $result->fetch()) {
548
-			$comment = $this->getCommentFromData($data);
549
-			$this->cache($comment);
550
-			$comments[] = $comment;
551
-		}
552
-		$result->closeCursor();
553
-
554
-		return $comments;
555
-	}
556
-
557
-	/**
558
-	 * @param $objectType string the object type, e.g. 'files'
559
-	 * @param $objectId string the id of the object
560
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
561
-	 * that may be returned
562
-	 * @param string $verb Limit the verb of the comment - Added in 14.0.0
563
-	 * @return Int
564
-	 * @since 9.0.0
565
-	 */
566
-	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '') {
567
-		$qb = $this->dbConn->getQueryBuilder();
568
-		$query = $qb->select($qb->func()->count('id'))
569
-			->from('comments')
570
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
571
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
572
-			->setParameter('type', $objectType)
573
-			->setParameter('id', $objectId);
574
-
575
-		if (!is_null($notOlderThan)) {
576
-			$query
577
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
578
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
579
-		}
580
-
581
-		if ($verb !== '') {
582
-			$query->andWhere($qb->expr()->eq('verb', $qb->createNamedParameter($verb)));
583
-		}
584
-
585
-		$resultStatement = $query->execute();
586
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
587
-		$resultStatement->closeCursor();
588
-		return (int)$data[0];
589
-	}
590
-
591
-	/**
592
-	 * Get the number of unread comments for all files in a folder
593
-	 *
594
-	 * @param int $folderId
595
-	 * @param IUser $user
596
-	 * @return array [$fileId => $unreadCount]
597
-	 *
598
-	 * @suppress SqlInjectionChecker
599
-	 */
600
-	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
601
-		$qb = $this->dbConn->getQueryBuilder();
602
-
603
-		$query = $qb->select('f.fileid')
604
-			->addSelect($qb->func()->count('c.id', 'num_ids'))
605
-			->from('filecache', 'f')
606
-			->leftJoin('f', 'comments', 'c', $qb->expr()->andX(
607
-				$qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)),
608
-				$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files'))
609
-			))
610
-			->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
611
-				$qb->expr()->eq('c.object_id', 'm.object_id'),
612
-				$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files'))
613
-			))
614
-			->where(
615
-				$qb->expr()->andX(
616
-					$qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)),
617
-					$qb->expr()->orX(
618
-						$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
619
-						$qb->expr()->isNull('c.object_type')
620
-					),
621
-					$qb->expr()->orX(
622
-						$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
623
-						$qb->expr()->isNull('m.object_type')
624
-					),
625
-					$qb->expr()->orX(
626
-						$qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())),
627
-						$qb->expr()->isNull('m.user_id')
628
-					),
629
-					$qb->expr()->orX(
630
-						$qb->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
631
-						$qb->expr()->isNull('m.marker_datetime')
632
-					)
633
-				)
634
-			)->groupBy('f.fileid');
635
-
636
-		$resultStatement = $query->execute();
637
-
638
-		$results = [];
639
-		while ($row = $resultStatement->fetch()) {
640
-			$results[$row['fileid']] = (int) $row['num_ids'];
641
-		}
642
-		$resultStatement->closeCursor();
643
-		return $results;
644
-	}
645
-
646
-	/**
647
-	 * creates a new comment and returns it. At this point of time, it is not
648
-	 * saved in the used data storage. Use save() after setting other fields
649
-	 * of the comment (e.g. message or verb).
650
-	 *
651
-	 * @param string $actorType the actor type (e.g. 'users')
652
-	 * @param string $actorId a user id
653
-	 * @param string $objectType the object type the comment is attached to
654
-	 * @param string $objectId the object id the comment is attached to
655
-	 * @return IComment
656
-	 * @since 9.0.0
657
-	 */
658
-	public function create($actorType, $actorId, $objectType, $objectId) {
659
-		$comment = new Comment();
660
-		$comment
661
-			->setActor($actorType, $actorId)
662
-			->setObject($objectType, $objectId);
663
-		return $comment;
664
-	}
665
-
666
-	/**
667
-	 * permanently deletes the comment specified by the ID
668
-	 *
669
-	 * When the comment has child comments, their parent ID will be changed to
670
-	 * the parent ID of the item that is to be deleted.
671
-	 *
672
-	 * @param string $id
673
-	 * @return bool
674
-	 * @throws \InvalidArgumentException
675
-	 * @since 9.0.0
676
-	 */
677
-	public function delete($id) {
678
-		if (!is_string($id)) {
679
-			throw new \InvalidArgumentException('Parameter must be string');
680
-		}
681
-
682
-		try {
683
-			$comment = $this->get($id);
684
-		} catch (\Exception $e) {
685
-			// Ignore exceptions, we just don't fire a hook then
686
-			$comment = null;
687
-		}
688
-
689
-		$qb = $this->dbConn->getQueryBuilder();
690
-		$query = $qb->delete('comments')
691
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
692
-			->setParameter('id', $id);
693
-
694
-		try {
695
-			$affectedRows = $query->execute();
696
-			$this->uncache($id);
697
-		} catch (DriverException $e) {
698
-			$this->logger->logException($e, ['app' => 'core_comments']);
699
-			return false;
700
-		}
701
-
702
-		if ($affectedRows > 0 && $comment instanceof IComment) {
703
-			$this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
704
-		}
705
-
706
-		return ($affectedRows > 0);
707
-	}
708
-
709
-	/**
710
-	 * saves the comment permanently
711
-	 *
712
-	 * if the supplied comment has an empty ID, a new entry comment will be
713
-	 * saved and the instance updated with the new ID.
714
-	 *
715
-	 * Otherwise, an existing comment will be updated.
716
-	 *
717
-	 * Throws NotFoundException when a comment that is to be updated does not
718
-	 * exist anymore at this point of time.
719
-	 *
720
-	 * @param IComment $comment
721
-	 * @return bool
722
-	 * @throws NotFoundException
723
-	 * @since 9.0.0
724
-	 */
725
-	public function save(IComment $comment) {
726
-		if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
727
-			$result = $this->insert($comment);
728
-		} else {
729
-			$result = $this->update($comment);
730
-		}
731
-
732
-		if ($result && !!$comment->getParentId()) {
733
-			$this->updateChildrenInformation(
734
-				$comment->getParentId(),
735
-				$comment->getCreationDateTime()
736
-			);
737
-			$this->cache($comment);
738
-		}
739
-
740
-		return $result;
741
-	}
742
-
743
-	/**
744
-	 * inserts the provided comment in the database
745
-	 *
746
-	 * @param IComment $comment
747
-	 * @return bool
748
-	 */
749
-	protected function insert(IComment $comment): bool {
750
-
751
-		try {
752
-			$result = $this->insertQuery($comment, true);
753
-		} catch (InvalidFieldNameException $e) {
754
-			// The reference id field was only added in Nextcloud 19.
755
-			// In order to not cause too long waiting times on the update,
756
-			// it was decided to only add it lazy, as it is also not a critical
757
-			// feature, but only helps to have a better experience while commenting.
758
-			// So in case the reference_id field is missing,
759
-			// we simply save the comment without that field.
760
-			$result = $this->insertQuery($comment, false);
761
-		}
762
-
763
-		return $result;
764
-	}
765
-
766
-	protected function insertQuery(IComment $comment, bool $tryWritingReferenceId): bool {
767
-		$qb = $this->dbConn->getQueryBuilder();
768
-
769
-		$values = [
770
-			'parent_id' => $qb->createNamedParameter($comment->getParentId()),
771
-			'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
772
-			'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
773
-			'actor_type' => $qb->createNamedParameter($comment->getActorType()),
774
-			'actor_id' => $qb->createNamedParameter($comment->getActorId()),
775
-			'message' => $qb->createNamedParameter($comment->getMessage()),
776
-			'verb' => $qb->createNamedParameter($comment->getVerb()),
777
-			'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
778
-			'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
779
-			'object_type' => $qb->createNamedParameter($comment->getObjectType()),
780
-			'object_id' => $qb->createNamedParameter($comment->getObjectId()),
781
-		];
782
-
783
-		if ($tryWritingReferenceId) {
784
-			$values['reference_id'] = $qb->createNamedParameter($comment->getReferenceId());
785
-		}
786
-
787
-		$affectedRows = $qb->insert('comments')
788
-			->values($values)
789
-			->execute();
790
-
791
-		if ($affectedRows > 0) {
792
-			$comment->setId((string)$qb->getLastInsertId());
793
-			$this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
794
-		}
795
-
796
-		return $affectedRows > 0;
797
-	}
798
-
799
-	/**
800
-	 * updates a Comment data row
801
-	 *
802
-	 * @param IComment $comment
803
-	 * @return bool
804
-	 * @throws NotFoundException
805
-	 */
806
-	protected function update(IComment $comment) {
807
-		// for properly working preUpdate Events we need the old comments as is
808
-		// in the DB and overcome caching. Also avoid that outdated information stays.
809
-		$this->uncache($comment->getId());
810
-		$this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
811
-		$this->uncache($comment->getId());
812
-
813
-		try {
814
-			$result = $this->updateQuery($comment, true);
815
-		} catch (InvalidFieldNameException $e) {
816
-			// See function insert() for explanation
817
-			$result = $this->updateQuery($comment, false);
818
-		}
819
-
820
-		$this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
821
-
822
-		return $result;
823
-	}
824
-
825
-	protected function updateQuery(IComment $comment, bool $tryWritingReferenceId): bool {
826
-		$qb = $this->dbConn->getQueryBuilder();
827
-		$qb
828
-			->update('comments')
829
-			->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
830
-			->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
831
-			->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
832
-			->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
833
-			->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
834
-			->set('message', $qb->createNamedParameter($comment->getMessage()))
835
-			->set('verb', $qb->createNamedParameter($comment->getVerb()))
836
-			->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
837
-			->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
838
-			->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
839
-			->set('object_id', $qb->createNamedParameter($comment->getObjectId()));
840
-
841
-		if ($tryWritingReferenceId) {
842
-			$qb->set('reference_id', $qb->createNamedParameter($comment->getReferenceId()));
843
-		}
844
-
845
-		$affectedRows = $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId())))
846
-			->execute();
847
-
848
-		if ($affectedRows === 0) {
849
-			throw new NotFoundException('Comment to update does ceased to exist');
850
-		}
851
-
852
-		return $affectedRows > 0;
853
-	}
854
-
855
-	/**
856
-	 * removes references to specific actor (e.g. on user delete) of a comment.
857
-	 * The comment itself must not get lost/deleted.
858
-	 *
859
-	 * @param string $actorType the actor type (e.g. 'users')
860
-	 * @param string $actorId a user id
861
-	 * @return boolean
862
-	 * @since 9.0.0
863
-	 */
864
-	public function deleteReferencesOfActor($actorType, $actorId) {
865
-		$this->checkRoleParameters('Actor', $actorType, $actorId);
866
-
867
-		$qb = $this->dbConn->getQueryBuilder();
868
-		$affectedRows = $qb
869
-			->update('comments')
870
-			->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
871
-			->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
872
-			->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
873
-			->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
874
-			->setParameter('type', $actorType)
875
-			->setParameter('id', $actorId)
876
-			->execute();
877
-
878
-		$this->commentsCache = [];
879
-
880
-		return is_int($affectedRows);
881
-	}
882
-
883
-	/**
884
-	 * deletes all comments made of a specific object (e.g. on file delete)
885
-	 *
886
-	 * @param string $objectType the object type (e.g. 'files')
887
-	 * @param string $objectId e.g. the file id
888
-	 * @return boolean
889
-	 * @since 9.0.0
890
-	 */
891
-	public function deleteCommentsAtObject($objectType, $objectId) {
892
-		$this->checkRoleParameters('Object', $objectType, $objectId);
893
-
894
-		$qb = $this->dbConn->getQueryBuilder();
895
-		$affectedRows = $qb
896
-			->delete('comments')
897
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
898
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
899
-			->setParameter('type', $objectType)
900
-			->setParameter('id', $objectId)
901
-			->execute();
902
-
903
-		$this->commentsCache = [];
904
-
905
-		return is_int($affectedRows);
906
-	}
907
-
908
-	/**
909
-	 * deletes the read markers for the specified user
910
-	 *
911
-	 * @param \OCP\IUser $user
912
-	 * @return bool
913
-	 * @since 9.0.0
914
-	 */
915
-	public function deleteReadMarksFromUser(IUser $user) {
916
-		$qb = $this->dbConn->getQueryBuilder();
917
-		$query = $qb->delete('comments_read_markers')
918
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
919
-			->setParameter('user_id', $user->getUID());
920
-
921
-		try {
922
-			$affectedRows = $query->execute();
923
-		} catch (DriverException $e) {
924
-			$this->logger->logException($e, ['app' => 'core_comments']);
925
-			return false;
926
-		}
927
-		return ($affectedRows > 0);
928
-	}
929
-
930
-	/**
931
-	 * sets the read marker for a given file to the specified date for the
932
-	 * provided user
933
-	 *
934
-	 * @param string $objectType
935
-	 * @param string $objectId
936
-	 * @param \DateTime $dateTime
937
-	 * @param IUser $user
938
-	 * @since 9.0.0
939
-	 * @suppress SqlInjectionChecker
940
-	 */
941
-	public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
942
-		$this->checkRoleParameters('Object', $objectType, $objectId);
943
-
944
-		$qb = $this->dbConn->getQueryBuilder();
945
-		$values = [
946
-			'user_id' => $qb->createNamedParameter($user->getUID()),
947
-			'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
948
-			'object_type' => $qb->createNamedParameter($objectType),
949
-			'object_id' => $qb->createNamedParameter($objectId),
950
-		];
951
-
952
-		// Strategy: try to update, if this does not return affected rows, do an insert.
953
-		$affectedRows = $qb
954
-			->update('comments_read_markers')
955
-			->set('user_id', $values['user_id'])
956
-			->set('marker_datetime', $values['marker_datetime'])
957
-			->set('object_type', $values['object_type'])
958
-			->set('object_id', $values['object_id'])
959
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
960
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
961
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
962
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
963
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
964
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
965
-			->execute();
966
-
967
-		if ($affectedRows > 0) {
968
-			return;
969
-		}
970
-
971
-		$qb->insert('comments_read_markers')
972
-			->values($values)
973
-			->execute();
974
-	}
975
-
976
-	/**
977
-	 * returns the read marker for a given file to the specified date for the
978
-	 * provided user. It returns null, when the marker is not present, i.e.
979
-	 * no comments were marked as read.
980
-	 *
981
-	 * @param string $objectType
982
-	 * @param string $objectId
983
-	 * @param IUser $user
984
-	 * @return \DateTime|null
985
-	 * @since 9.0.0
986
-	 */
987
-	public function getReadMark($objectType, $objectId, IUser $user) {
988
-		$qb = $this->dbConn->getQueryBuilder();
989
-		$resultStatement = $qb->select('marker_datetime')
990
-			->from('comments_read_markers')
991
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
992
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
993
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
994
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
995
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
996
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
997
-			->execute();
998
-
999
-		$data = $resultStatement->fetch();
1000
-		$resultStatement->closeCursor();
1001
-		if (!$data || is_null($data['marker_datetime'])) {
1002
-			return null;
1003
-		}
1004
-
1005
-		return new \DateTime($data['marker_datetime']);
1006
-	}
1007
-
1008
-	/**
1009
-	 * deletes the read markers on the specified object
1010
-	 *
1011
-	 * @param string $objectType
1012
-	 * @param string $objectId
1013
-	 * @return bool
1014
-	 * @since 9.0.0
1015
-	 */
1016
-	public function deleteReadMarksOnObject($objectType, $objectId) {
1017
-		$this->checkRoleParameters('Object', $objectType, $objectId);
1018
-
1019
-		$qb = $this->dbConn->getQueryBuilder();
1020
-		$query = $qb->delete('comments_read_markers')
1021
-			->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
1022
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
1023
-			->setParameter('object_type', $objectType)
1024
-			->setParameter('object_id', $objectId);
1025
-
1026
-		try {
1027
-			$affectedRows = $query->execute();
1028
-		} catch (DriverException $e) {
1029
-			$this->logger->logException($e, ['app' => 'core_comments']);
1030
-			return false;
1031
-		}
1032
-		return ($affectedRows > 0);
1033
-	}
1034
-
1035
-	/**
1036
-	 * registers an Entity to the manager, so event notifications can be send
1037
-	 * to consumers of the comments infrastructure
1038
-	 *
1039
-	 * @param \Closure $closure
1040
-	 */
1041
-	public function registerEventHandler(\Closure $closure) {
1042
-		$this->eventHandlerClosures[] = $closure;
1043
-		$this->eventHandlers = [];
1044
-	}
1045
-
1046
-	/**
1047
-	 * registers a method that resolves an ID to a display name for a given type
1048
-	 *
1049
-	 * @param string $type
1050
-	 * @param \Closure $closure
1051
-	 * @throws \OutOfBoundsException
1052
-	 * @since 11.0.0
1053
-	 *
1054
-	 * Only one resolver shall be registered per type. Otherwise a
1055
-	 * \OutOfBoundsException has to thrown.
1056
-	 */
1057
-	public function registerDisplayNameResolver($type, \Closure $closure) {
1058
-		if (!is_string($type)) {
1059
-			throw new \InvalidArgumentException('String expected.');
1060
-		}
1061
-		if (isset($this->displayNameResolvers[$type])) {
1062
-			throw new \OutOfBoundsException('Displayname resolver for this type already registered');
1063
-		}
1064
-		$this->displayNameResolvers[$type] = $closure;
1065
-	}
1066
-
1067
-	/**
1068
-	 * resolves a given ID of a given Type to a display name.
1069
-	 *
1070
-	 * @param string $type
1071
-	 * @param string $id
1072
-	 * @return string
1073
-	 * @throws \OutOfBoundsException
1074
-	 * @since 11.0.0
1075
-	 *
1076
-	 * If a provided type was not registered, an \OutOfBoundsException shall
1077
-	 * be thrown. It is upon the resolver discretion what to return of the
1078
-	 * provided ID is unknown. It must be ensured that a string is returned.
1079
-	 */
1080
-	public function resolveDisplayName($type, $id) {
1081
-		if (!is_string($type)) {
1082
-			throw new \InvalidArgumentException('String expected.');
1083
-		}
1084
-		if (!isset($this->displayNameResolvers[$type])) {
1085
-			throw new \OutOfBoundsException('No Displayname resolver for this type registered');
1086
-		}
1087
-		return (string)$this->displayNameResolvers[$type]($id);
1088
-	}
1089
-
1090
-	/**
1091
-	 * returns valid, registered entities
1092
-	 *
1093
-	 * @return \OCP\Comments\ICommentsEventHandler[]
1094
-	 */
1095
-	private function getEventHandlers() {
1096
-		if (!empty($this->eventHandlers)) {
1097
-			return $this->eventHandlers;
1098
-		}
1099
-
1100
-		$this->eventHandlers = [];
1101
-		foreach ($this->eventHandlerClosures as $name => $closure) {
1102
-			$entity = $closure();
1103
-			if (!($entity instanceof ICommentsEventHandler)) {
1104
-				throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
1105
-			}
1106
-			$this->eventHandlers[$name] = $entity;
1107
-		}
1108
-
1109
-		return $this->eventHandlers;
1110
-	}
1111
-
1112
-	/**
1113
-	 * sends notifications to the registered entities
1114
-	 *
1115
-	 * @param $eventType
1116
-	 * @param IComment $comment
1117
-	 */
1118
-	private function sendEvent($eventType, IComment $comment) {
1119
-		$entities = $this->getEventHandlers();
1120
-		$event = new CommentsEvent($eventType, $comment);
1121
-		foreach ($entities as $entity) {
1122
-			$entity->handle($event);
1123
-		}
1124
-	}
46
+    /** @var  IDBConnection */
47
+    protected $dbConn;
48
+
49
+    /** @var  ILogger */
50
+    protected $logger;
51
+
52
+    /** @var IConfig */
53
+    protected $config;
54
+
55
+    /** @var IComment[] */
56
+    protected $commentsCache = [];
57
+
58
+    /** @var  \Closure[] */
59
+    protected $eventHandlerClosures = [];
60
+
61
+    /** @var  ICommentsEventHandler[] */
62
+    protected $eventHandlers = [];
63
+
64
+    /** @var \Closure[] */
65
+    protected $displayNameResolvers = [];
66
+
67
+    /**
68
+     * Manager constructor.
69
+     *
70
+     * @param IDBConnection $dbConn
71
+     * @param ILogger $logger
72
+     * @param IConfig $config
73
+     */
74
+    public function __construct(
75
+        IDBConnection $dbConn,
76
+        ILogger $logger,
77
+        IConfig $config
78
+    ) {
79
+        $this->dbConn = $dbConn;
80
+        $this->logger = $logger;
81
+        $this->config = $config;
82
+    }
83
+
84
+    /**
85
+     * converts data base data into PHP native, proper types as defined by
86
+     * IComment interface.
87
+     *
88
+     * @param array $data
89
+     * @return array
90
+     */
91
+    protected function normalizeDatabaseData(array $data) {
92
+        $data['id'] = (string)$data['id'];
93
+        $data['parent_id'] = (string)$data['parent_id'];
94
+        $data['topmost_parent_id'] = (string)$data['topmost_parent_id'];
95
+        $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
96
+        if (!is_null($data['latest_child_timestamp'])) {
97
+            $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
98
+        }
99
+        $data['children_count'] = (int)$data['children_count'];
100
+        $data['reference_id'] = $data['reference_id'] ?? null;
101
+        return $data;
102
+    }
103
+
104
+
105
+    /**
106
+     * @param array $data
107
+     * @return IComment
108
+     */
109
+    public function getCommentFromData(array $data): IComment {
110
+        return new Comment($this->normalizeDatabaseData($data));
111
+    }
112
+
113
+    /**
114
+     * prepares a comment for an insert or update operation after making sure
115
+     * all necessary fields have a value assigned.
116
+     *
117
+     * @param IComment $comment
118
+     * @return IComment returns the same updated IComment instance as provided
119
+     *                  by parameter for convenience
120
+     * @throws \UnexpectedValueException
121
+     */
122
+    protected function prepareCommentForDatabaseWrite(IComment $comment) {
123
+        if (!$comment->getActorType()
124
+            || $comment->getActorId() === ''
125
+            || !$comment->getObjectType()
126
+            || $comment->getObjectId() === ''
127
+            || !$comment->getVerb()
128
+        ) {
129
+            throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
130
+        }
131
+
132
+        if ($comment->getId() === '') {
133
+            $comment->setChildrenCount(0);
134
+            $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
135
+            $comment->setLatestChildDateTime(null);
136
+        }
137
+
138
+        if (is_null($comment->getCreationDateTime())) {
139
+            $comment->setCreationDateTime(new \DateTime());
140
+        }
141
+
142
+        if ($comment->getParentId() !== '0') {
143
+            $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
144
+        } else {
145
+            $comment->setTopmostParentId('0');
146
+        }
147
+
148
+        $this->cache($comment);
149
+
150
+        return $comment;
151
+    }
152
+
153
+    /**
154
+     * returns the topmost parent id of a given comment identified by ID
155
+     *
156
+     * @param string $id
157
+     * @return string
158
+     * @throws NotFoundException
159
+     */
160
+    protected function determineTopmostParentId($id) {
161
+        $comment = $this->get($id);
162
+        if ($comment->getParentId() === '0') {
163
+            return $comment->getId();
164
+        }
165
+
166
+        return $this->determineTopmostParentId($comment->getParentId());
167
+    }
168
+
169
+    /**
170
+     * updates child information of a comment
171
+     *
172
+     * @param string $id
173
+     * @param \DateTime $cDateTime the date time of the most recent child
174
+     * @throws NotFoundException
175
+     */
176
+    protected function updateChildrenInformation($id, \DateTime $cDateTime) {
177
+        $qb = $this->dbConn->getQueryBuilder();
178
+        $query = $qb->select($qb->func()->count('id'))
179
+            ->from('comments')
180
+            ->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
181
+            ->setParameter('id', $id);
182
+
183
+        $resultStatement = $query->execute();
184
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
185
+        $resultStatement->closeCursor();
186
+        $children = (int)$data[0];
187
+
188
+        $comment = $this->get($id);
189
+        $comment->setChildrenCount($children);
190
+        $comment->setLatestChildDateTime($cDateTime);
191
+        $this->save($comment);
192
+    }
193
+
194
+    /**
195
+     * Tests whether actor or object type and id parameters are acceptable.
196
+     * Throws exception if not.
197
+     *
198
+     * @param string $role
199
+     * @param string $type
200
+     * @param string $id
201
+     * @throws \InvalidArgumentException
202
+     */
203
+    protected function checkRoleParameters($role, $type, $id) {
204
+        if (
205
+            !is_string($type) || empty($type)
206
+            || !is_string($id) || empty($id)
207
+        ) {
208
+            throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
209
+        }
210
+    }
211
+
212
+    /**
213
+     * run-time caches a comment
214
+     *
215
+     * @param IComment $comment
216
+     */
217
+    protected function cache(IComment $comment) {
218
+        $id = $comment->getId();
219
+        if (empty($id)) {
220
+            return;
221
+        }
222
+        $this->commentsCache[(string)$id] = $comment;
223
+    }
224
+
225
+    /**
226
+     * removes an entry from the comments run time cache
227
+     *
228
+     * @param mixed $id the comment's id
229
+     */
230
+    protected function uncache($id) {
231
+        $id = (string)$id;
232
+        if (isset($this->commentsCache[$id])) {
233
+            unset($this->commentsCache[$id]);
234
+        }
235
+    }
236
+
237
+    /**
238
+     * returns a comment instance
239
+     *
240
+     * @param string $id the ID of the comment
241
+     * @return IComment
242
+     * @throws NotFoundException
243
+     * @throws \InvalidArgumentException
244
+     * @since 9.0.0
245
+     */
246
+    public function get($id) {
247
+        if ((int)$id === 0) {
248
+            throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
249
+        }
250
+
251
+        if (isset($this->commentsCache[$id])) {
252
+            return $this->commentsCache[$id];
253
+        }
254
+
255
+        $qb = $this->dbConn->getQueryBuilder();
256
+        $resultStatement = $qb->select('*')
257
+            ->from('comments')
258
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
259
+            ->setParameter('id', $id, IQueryBuilder::PARAM_INT)
260
+            ->execute();
261
+
262
+        $data = $resultStatement->fetch();
263
+        $resultStatement->closeCursor();
264
+        if (!$data) {
265
+            throw new NotFoundException();
266
+        }
267
+
268
+
269
+        $comment = $this->getCommentFromData($data);
270
+        $this->cache($comment);
271
+        return $comment;
272
+    }
273
+
274
+    /**
275
+     * returns the comment specified by the id and all it's child comments.
276
+     * At this point of time, we do only support one level depth.
277
+     *
278
+     * @param string $id
279
+     * @param int $limit max number of entries to return, 0 returns all
280
+     * @param int $offset the start entry
281
+     * @return array
282
+     * @since 9.0.0
283
+     *
284
+     * The return array looks like this
285
+     * [
286
+     *   'comment' => IComment, // root comment
287
+     *   'replies' =>
288
+     *   [
289
+     *     0 =>
290
+     *     [
291
+     *       'comment' => IComment,
292
+     *       'replies' => []
293
+     *     ]
294
+     *     1 =>
295
+     *     [
296
+     *       'comment' => IComment,
297
+     *       'replies'=> []
298
+     *     ],
299
+     *     …
300
+     *   ]
301
+     * ]
302
+     */
303
+    public function getTree($id, $limit = 0, $offset = 0) {
304
+        $tree = [];
305
+        $tree['comment'] = $this->get($id);
306
+        $tree['replies'] = [];
307
+
308
+        $qb = $this->dbConn->getQueryBuilder();
309
+        $query = $qb->select('*')
310
+            ->from('comments')
311
+            ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
312
+            ->orderBy('creation_timestamp', 'DESC')
313
+            ->setParameter('id', $id);
314
+
315
+        if ($limit > 0) {
316
+            $query->setMaxResults($limit);
317
+        }
318
+        if ($offset > 0) {
319
+            $query->setFirstResult($offset);
320
+        }
321
+
322
+        $resultStatement = $query->execute();
323
+        while ($data = $resultStatement->fetch()) {
324
+            $comment = $this->getCommentFromData($data);
325
+            $this->cache($comment);
326
+            $tree['replies'][] = [
327
+                'comment' => $comment,
328
+                'replies' => []
329
+            ];
330
+        }
331
+        $resultStatement->closeCursor();
332
+
333
+        return $tree;
334
+    }
335
+
336
+    /**
337
+     * returns comments for a specific object (e.g. a file).
338
+     *
339
+     * The sort order is always newest to oldest.
340
+     *
341
+     * @param string $objectType the object type, e.g. 'files'
342
+     * @param string $objectId the id of the object
343
+     * @param int $limit optional, number of maximum comments to be returned. if
344
+     * not specified, all comments are returned.
345
+     * @param int $offset optional, starting point
346
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
347
+     * that may be returned
348
+     * @return IComment[]
349
+     * @since 9.0.0
350
+     */
351
+    public function getForObject(
352
+        $objectType,
353
+        $objectId,
354
+        $limit = 0,
355
+        $offset = 0,
356
+        \DateTime $notOlderThan = null
357
+    ) {
358
+        $comments = [];
359
+
360
+        $qb = $this->dbConn->getQueryBuilder();
361
+        $query = $qb->select('*')
362
+            ->from('comments')
363
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
364
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
365
+            ->orderBy('creation_timestamp', 'DESC')
366
+            ->setParameter('type', $objectType)
367
+            ->setParameter('id', $objectId);
368
+
369
+        if ($limit > 0) {
370
+            $query->setMaxResults($limit);
371
+        }
372
+        if ($offset > 0) {
373
+            $query->setFirstResult($offset);
374
+        }
375
+        if (!is_null($notOlderThan)) {
376
+            $query
377
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
378
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
379
+        }
380
+
381
+        $resultStatement = $query->execute();
382
+        while ($data = $resultStatement->fetch()) {
383
+            $comment = $this->getCommentFromData($data);
384
+            $this->cache($comment);
385
+            $comments[] = $comment;
386
+        }
387
+        $resultStatement->closeCursor();
388
+
389
+        return $comments;
390
+    }
391
+
392
+    /**
393
+     * @param string $objectType the object type, e.g. 'files'
394
+     * @param string $objectId the id of the object
395
+     * @param int $lastKnownCommentId the last known comment (will be used as offset)
396
+     * @param string $sortDirection direction of the comments (`asc` or `desc`)
397
+     * @param int $limit optional, number of maximum comments to be returned. if
398
+     * set to 0, all comments are returned.
399
+     * @return IComment[]
400
+     * @return array
401
+     */
402
+    public function getForObjectSince(
403
+        string $objectType,
404
+        string $objectId,
405
+        int $lastKnownCommentId,
406
+        string $sortDirection = 'asc',
407
+        int $limit = 30
408
+    ): array {
409
+        $comments = [];
410
+
411
+        $query = $this->dbConn->getQueryBuilder();
412
+        $query->select('*')
413
+            ->from('comments')
414
+            ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
415
+            ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
416
+            ->orderBy('creation_timestamp', $sortDirection === 'desc' ? 'DESC' : 'ASC')
417
+            ->addOrderBy('id', $sortDirection === 'desc' ? 'DESC' : 'ASC');
418
+
419
+        if ($limit > 0) {
420
+            $query->setMaxResults($limit);
421
+        }
422
+
423
+        $lastKnownComment = $lastKnownCommentId > 0 ? $this->getLastKnownComment(
424
+            $objectType,
425
+            $objectId,
426
+            $lastKnownCommentId
427
+        ) : null;
428
+        if ($lastKnownComment instanceof IComment) {
429
+            $lastKnownCommentDateTime = $lastKnownComment->getCreationDateTime();
430
+            if ($sortDirection === 'desc') {
431
+                $query->andWhere(
432
+                    $query->expr()->orX(
433
+                        $query->expr()->lt(
434
+                            'creation_timestamp',
435
+                            $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
436
+                            IQueryBuilder::PARAM_DATE
437
+                        ),
438
+                        $query->expr()->andX(
439
+                            $query->expr()->eq(
440
+                                'creation_timestamp',
441
+                                $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
442
+                                IQueryBuilder::PARAM_DATE
443
+                            ),
444
+                            $query->expr()->lt('id', $query->createNamedParameter($lastKnownCommentId))
445
+                        )
446
+                    )
447
+                );
448
+            } else {
449
+                $query->andWhere(
450
+                    $query->expr()->orX(
451
+                        $query->expr()->gt(
452
+                            'creation_timestamp',
453
+                            $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
454
+                            IQueryBuilder::PARAM_DATE
455
+                        ),
456
+                        $query->expr()->andX(
457
+                            $query->expr()->eq(
458
+                                'creation_timestamp',
459
+                                $query->createNamedParameter($lastKnownCommentDateTime, IQueryBuilder::PARAM_DATE),
460
+                                IQueryBuilder::PARAM_DATE
461
+                            ),
462
+                            $query->expr()->gt('id', $query->createNamedParameter($lastKnownCommentId))
463
+                        )
464
+                    )
465
+                );
466
+            }
467
+        }
468
+
469
+        $resultStatement = $query->execute();
470
+        while ($data = $resultStatement->fetch()) {
471
+            $comment = $this->getCommentFromData($data);
472
+            $this->cache($comment);
473
+            $comments[] = $comment;
474
+        }
475
+        $resultStatement->closeCursor();
476
+
477
+        return $comments;
478
+    }
479
+
480
+    /**
481
+     * @param string $objectType the object type, e.g. 'files'
482
+     * @param string $objectId the id of the object
483
+     * @param int $id the comment to look for
484
+     * @return Comment|null
485
+     */
486
+    protected function getLastKnownComment(string $objectType,
487
+                                            string $objectId,
488
+                                            int $id) {
489
+        $query = $this->dbConn->getQueryBuilder();
490
+        $query->select('*')
491
+            ->from('comments')
492
+            ->where($query->expr()->eq('object_type', $query->createNamedParameter($objectType)))
493
+            ->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)))
494
+            ->andWhere($query->expr()->eq('id', $query->createNamedParameter($id, IQueryBuilder::PARAM_INT)));
495
+
496
+        $result = $query->execute();
497
+        $row = $result->fetch();
498
+        $result->closeCursor();
499
+
500
+        if ($row) {
501
+            $comment = $this->getCommentFromData($row);
502
+            $this->cache($comment);
503
+            return $comment;
504
+        }
505
+
506
+        return null;
507
+    }
508
+
509
+    /**
510
+     * Search for comments with a given content
511
+     *
512
+     * @param string $search content to search for
513
+     * @param string $objectType Limit the search by object type
514
+     * @param string $objectId Limit the search by object id
515
+     * @param string $verb Limit the verb of the comment
516
+     * @param int $offset
517
+     * @param int $limit
518
+     * @return IComment[]
519
+     */
520
+    public function search(string $search, string $objectType, string $objectId, string $verb, int $offset, int $limit = 50): array {
521
+        $query = $this->dbConn->getQueryBuilder();
522
+
523
+        $query->select('*')
524
+            ->from('comments')
525
+            ->where($query->expr()->iLike('message', $query->createNamedParameter(
526
+                '%' . $this->dbConn->escapeLikeParameter($search). '%'
527
+            )))
528
+            ->orderBy('creation_timestamp', 'DESC')
529
+            ->addOrderBy('id', 'DESC')
530
+            ->setMaxResults($limit);
531
+
532
+        if ($objectType !== '') {
533
+            $query->andWhere($query->expr()->eq('object_type', $query->createNamedParameter($objectType)));
534
+        }
535
+        if ($objectId !== '') {
536
+            $query->andWhere($query->expr()->eq('object_id', $query->createNamedParameter($objectId)));
537
+        }
538
+        if ($verb !== '') {
539
+            $query->andWhere($query->expr()->eq('verb', $query->createNamedParameter($verb)));
540
+        }
541
+        if ($offset !== 0) {
542
+            $query->setFirstResult($offset);
543
+        }
544
+
545
+        $comments = [];
546
+        $result = $query->execute();
547
+        while ($data = $result->fetch()) {
548
+            $comment = $this->getCommentFromData($data);
549
+            $this->cache($comment);
550
+            $comments[] = $comment;
551
+        }
552
+        $result->closeCursor();
553
+
554
+        return $comments;
555
+    }
556
+
557
+    /**
558
+     * @param $objectType string the object type, e.g. 'files'
559
+     * @param $objectId string the id of the object
560
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
561
+     * that may be returned
562
+     * @param string $verb Limit the verb of the comment - Added in 14.0.0
563
+     * @return Int
564
+     * @since 9.0.0
565
+     */
566
+    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null, $verb = '') {
567
+        $qb = $this->dbConn->getQueryBuilder();
568
+        $query = $qb->select($qb->func()->count('id'))
569
+            ->from('comments')
570
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
571
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
572
+            ->setParameter('type', $objectType)
573
+            ->setParameter('id', $objectId);
574
+
575
+        if (!is_null($notOlderThan)) {
576
+            $query
577
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
578
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
579
+        }
580
+
581
+        if ($verb !== '') {
582
+            $query->andWhere($qb->expr()->eq('verb', $qb->createNamedParameter($verb)));
583
+        }
584
+
585
+        $resultStatement = $query->execute();
586
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
587
+        $resultStatement->closeCursor();
588
+        return (int)$data[0];
589
+    }
590
+
591
+    /**
592
+     * Get the number of unread comments for all files in a folder
593
+     *
594
+     * @param int $folderId
595
+     * @param IUser $user
596
+     * @return array [$fileId => $unreadCount]
597
+     *
598
+     * @suppress SqlInjectionChecker
599
+     */
600
+    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
601
+        $qb = $this->dbConn->getQueryBuilder();
602
+
603
+        $query = $qb->select('f.fileid')
604
+            ->addSelect($qb->func()->count('c.id', 'num_ids'))
605
+            ->from('filecache', 'f')
606
+            ->leftJoin('f', 'comments', 'c', $qb->expr()->andX(
607
+                $qb->expr()->eq('f.fileid', $qb->expr()->castColumn('c.object_id', IQueryBuilder::PARAM_INT)),
608
+                $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files'))
609
+            ))
610
+            ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
611
+                $qb->expr()->eq('c.object_id', 'm.object_id'),
612
+                $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files'))
613
+            ))
614
+            ->where(
615
+                $qb->expr()->andX(
616
+                    $qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)),
617
+                    $qb->expr()->orX(
618
+                        $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
619
+                        $qb->expr()->isNull('c.object_type')
620
+                    ),
621
+                    $qb->expr()->orX(
622
+                        $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
623
+                        $qb->expr()->isNull('m.object_type')
624
+                    ),
625
+                    $qb->expr()->orX(
626
+                        $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID())),
627
+                        $qb->expr()->isNull('m.user_id')
628
+                    ),
629
+                    $qb->expr()->orX(
630
+                        $qb->expr()->gt('c.creation_timestamp', 'm.marker_datetime'),
631
+                        $qb->expr()->isNull('m.marker_datetime')
632
+                    )
633
+                )
634
+            )->groupBy('f.fileid');
635
+
636
+        $resultStatement = $query->execute();
637
+
638
+        $results = [];
639
+        while ($row = $resultStatement->fetch()) {
640
+            $results[$row['fileid']] = (int) $row['num_ids'];
641
+        }
642
+        $resultStatement->closeCursor();
643
+        return $results;
644
+    }
645
+
646
+    /**
647
+     * creates a new comment and returns it. At this point of time, it is not
648
+     * saved in the used data storage. Use save() after setting other fields
649
+     * of the comment (e.g. message or verb).
650
+     *
651
+     * @param string $actorType the actor type (e.g. 'users')
652
+     * @param string $actorId a user id
653
+     * @param string $objectType the object type the comment is attached to
654
+     * @param string $objectId the object id the comment is attached to
655
+     * @return IComment
656
+     * @since 9.0.0
657
+     */
658
+    public function create($actorType, $actorId, $objectType, $objectId) {
659
+        $comment = new Comment();
660
+        $comment
661
+            ->setActor($actorType, $actorId)
662
+            ->setObject($objectType, $objectId);
663
+        return $comment;
664
+    }
665
+
666
+    /**
667
+     * permanently deletes the comment specified by the ID
668
+     *
669
+     * When the comment has child comments, their parent ID will be changed to
670
+     * the parent ID of the item that is to be deleted.
671
+     *
672
+     * @param string $id
673
+     * @return bool
674
+     * @throws \InvalidArgumentException
675
+     * @since 9.0.0
676
+     */
677
+    public function delete($id) {
678
+        if (!is_string($id)) {
679
+            throw new \InvalidArgumentException('Parameter must be string');
680
+        }
681
+
682
+        try {
683
+            $comment = $this->get($id);
684
+        } catch (\Exception $e) {
685
+            // Ignore exceptions, we just don't fire a hook then
686
+            $comment = null;
687
+        }
688
+
689
+        $qb = $this->dbConn->getQueryBuilder();
690
+        $query = $qb->delete('comments')
691
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
692
+            ->setParameter('id', $id);
693
+
694
+        try {
695
+            $affectedRows = $query->execute();
696
+            $this->uncache($id);
697
+        } catch (DriverException $e) {
698
+            $this->logger->logException($e, ['app' => 'core_comments']);
699
+            return false;
700
+        }
701
+
702
+        if ($affectedRows > 0 && $comment instanceof IComment) {
703
+            $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
704
+        }
705
+
706
+        return ($affectedRows > 0);
707
+    }
708
+
709
+    /**
710
+     * saves the comment permanently
711
+     *
712
+     * if the supplied comment has an empty ID, a new entry comment will be
713
+     * saved and the instance updated with the new ID.
714
+     *
715
+     * Otherwise, an existing comment will be updated.
716
+     *
717
+     * Throws NotFoundException when a comment that is to be updated does not
718
+     * exist anymore at this point of time.
719
+     *
720
+     * @param IComment $comment
721
+     * @return bool
722
+     * @throws NotFoundException
723
+     * @since 9.0.0
724
+     */
725
+    public function save(IComment $comment) {
726
+        if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
727
+            $result = $this->insert($comment);
728
+        } else {
729
+            $result = $this->update($comment);
730
+        }
731
+
732
+        if ($result && !!$comment->getParentId()) {
733
+            $this->updateChildrenInformation(
734
+                $comment->getParentId(),
735
+                $comment->getCreationDateTime()
736
+            );
737
+            $this->cache($comment);
738
+        }
739
+
740
+        return $result;
741
+    }
742
+
743
+    /**
744
+     * inserts the provided comment in the database
745
+     *
746
+     * @param IComment $comment
747
+     * @return bool
748
+     */
749
+    protected function insert(IComment $comment): bool {
750
+
751
+        try {
752
+            $result = $this->insertQuery($comment, true);
753
+        } catch (InvalidFieldNameException $e) {
754
+            // The reference id field was only added in Nextcloud 19.
755
+            // In order to not cause too long waiting times on the update,
756
+            // it was decided to only add it lazy, as it is also not a critical
757
+            // feature, but only helps to have a better experience while commenting.
758
+            // So in case the reference_id field is missing,
759
+            // we simply save the comment without that field.
760
+            $result = $this->insertQuery($comment, false);
761
+        }
762
+
763
+        return $result;
764
+    }
765
+
766
+    protected function insertQuery(IComment $comment, bool $tryWritingReferenceId): bool {
767
+        $qb = $this->dbConn->getQueryBuilder();
768
+
769
+        $values = [
770
+            'parent_id' => $qb->createNamedParameter($comment->getParentId()),
771
+            'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
772
+            'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
773
+            'actor_type' => $qb->createNamedParameter($comment->getActorType()),
774
+            'actor_id' => $qb->createNamedParameter($comment->getActorId()),
775
+            'message' => $qb->createNamedParameter($comment->getMessage()),
776
+            'verb' => $qb->createNamedParameter($comment->getVerb()),
777
+            'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
778
+            'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
779
+            'object_type' => $qb->createNamedParameter($comment->getObjectType()),
780
+            'object_id' => $qb->createNamedParameter($comment->getObjectId()),
781
+        ];
782
+
783
+        if ($tryWritingReferenceId) {
784
+            $values['reference_id'] = $qb->createNamedParameter($comment->getReferenceId());
785
+        }
786
+
787
+        $affectedRows = $qb->insert('comments')
788
+            ->values($values)
789
+            ->execute();
790
+
791
+        if ($affectedRows > 0) {
792
+            $comment->setId((string)$qb->getLastInsertId());
793
+            $this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
794
+        }
795
+
796
+        return $affectedRows > 0;
797
+    }
798
+
799
+    /**
800
+     * updates a Comment data row
801
+     *
802
+     * @param IComment $comment
803
+     * @return bool
804
+     * @throws NotFoundException
805
+     */
806
+    protected function update(IComment $comment) {
807
+        // for properly working preUpdate Events we need the old comments as is
808
+        // in the DB and overcome caching. Also avoid that outdated information stays.
809
+        $this->uncache($comment->getId());
810
+        $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
811
+        $this->uncache($comment->getId());
812
+
813
+        try {
814
+            $result = $this->updateQuery($comment, true);
815
+        } catch (InvalidFieldNameException $e) {
816
+            // See function insert() for explanation
817
+            $result = $this->updateQuery($comment, false);
818
+        }
819
+
820
+        $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
821
+
822
+        return $result;
823
+    }
824
+
825
+    protected function updateQuery(IComment $comment, bool $tryWritingReferenceId): bool {
826
+        $qb = $this->dbConn->getQueryBuilder();
827
+        $qb
828
+            ->update('comments')
829
+            ->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
830
+            ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
831
+            ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
832
+            ->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
833
+            ->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
834
+            ->set('message', $qb->createNamedParameter($comment->getMessage()))
835
+            ->set('verb', $qb->createNamedParameter($comment->getVerb()))
836
+            ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
837
+            ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
838
+            ->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
839
+            ->set('object_id', $qb->createNamedParameter($comment->getObjectId()));
840
+
841
+        if ($tryWritingReferenceId) {
842
+            $qb->set('reference_id', $qb->createNamedParameter($comment->getReferenceId()));
843
+        }
844
+
845
+        $affectedRows = $qb->where($qb->expr()->eq('id', $qb->createNamedParameter($comment->getId())))
846
+            ->execute();
847
+
848
+        if ($affectedRows === 0) {
849
+            throw new NotFoundException('Comment to update does ceased to exist');
850
+        }
851
+
852
+        return $affectedRows > 0;
853
+    }
854
+
855
+    /**
856
+     * removes references to specific actor (e.g. on user delete) of a comment.
857
+     * The comment itself must not get lost/deleted.
858
+     *
859
+     * @param string $actorType the actor type (e.g. 'users')
860
+     * @param string $actorId a user id
861
+     * @return boolean
862
+     * @since 9.0.0
863
+     */
864
+    public function deleteReferencesOfActor($actorType, $actorId) {
865
+        $this->checkRoleParameters('Actor', $actorType, $actorId);
866
+
867
+        $qb = $this->dbConn->getQueryBuilder();
868
+        $affectedRows = $qb
869
+            ->update('comments')
870
+            ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
871
+            ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
872
+            ->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
873
+            ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
874
+            ->setParameter('type', $actorType)
875
+            ->setParameter('id', $actorId)
876
+            ->execute();
877
+
878
+        $this->commentsCache = [];
879
+
880
+        return is_int($affectedRows);
881
+    }
882
+
883
+    /**
884
+     * deletes all comments made of a specific object (e.g. on file delete)
885
+     *
886
+     * @param string $objectType the object type (e.g. 'files')
887
+     * @param string $objectId e.g. the file id
888
+     * @return boolean
889
+     * @since 9.0.0
890
+     */
891
+    public function deleteCommentsAtObject($objectType, $objectId) {
892
+        $this->checkRoleParameters('Object', $objectType, $objectId);
893
+
894
+        $qb = $this->dbConn->getQueryBuilder();
895
+        $affectedRows = $qb
896
+            ->delete('comments')
897
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
898
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
899
+            ->setParameter('type', $objectType)
900
+            ->setParameter('id', $objectId)
901
+            ->execute();
902
+
903
+        $this->commentsCache = [];
904
+
905
+        return is_int($affectedRows);
906
+    }
907
+
908
+    /**
909
+     * deletes the read markers for the specified user
910
+     *
911
+     * @param \OCP\IUser $user
912
+     * @return bool
913
+     * @since 9.0.0
914
+     */
915
+    public function deleteReadMarksFromUser(IUser $user) {
916
+        $qb = $this->dbConn->getQueryBuilder();
917
+        $query = $qb->delete('comments_read_markers')
918
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
919
+            ->setParameter('user_id', $user->getUID());
920
+
921
+        try {
922
+            $affectedRows = $query->execute();
923
+        } catch (DriverException $e) {
924
+            $this->logger->logException($e, ['app' => 'core_comments']);
925
+            return false;
926
+        }
927
+        return ($affectedRows > 0);
928
+    }
929
+
930
+    /**
931
+     * sets the read marker for a given file to the specified date for the
932
+     * provided user
933
+     *
934
+     * @param string $objectType
935
+     * @param string $objectId
936
+     * @param \DateTime $dateTime
937
+     * @param IUser $user
938
+     * @since 9.0.0
939
+     * @suppress SqlInjectionChecker
940
+     */
941
+    public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
942
+        $this->checkRoleParameters('Object', $objectType, $objectId);
943
+
944
+        $qb = $this->dbConn->getQueryBuilder();
945
+        $values = [
946
+            'user_id' => $qb->createNamedParameter($user->getUID()),
947
+            'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
948
+            'object_type' => $qb->createNamedParameter($objectType),
949
+            'object_id' => $qb->createNamedParameter($objectId),
950
+        ];
951
+
952
+        // Strategy: try to update, if this does not return affected rows, do an insert.
953
+        $affectedRows = $qb
954
+            ->update('comments_read_markers')
955
+            ->set('user_id', $values['user_id'])
956
+            ->set('marker_datetime', $values['marker_datetime'])
957
+            ->set('object_type', $values['object_type'])
958
+            ->set('object_id', $values['object_id'])
959
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
960
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
961
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
962
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
963
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
964
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
965
+            ->execute();
966
+
967
+        if ($affectedRows > 0) {
968
+            return;
969
+        }
970
+
971
+        $qb->insert('comments_read_markers')
972
+            ->values($values)
973
+            ->execute();
974
+    }
975
+
976
+    /**
977
+     * returns the read marker for a given file to the specified date for the
978
+     * provided user. It returns null, when the marker is not present, i.e.
979
+     * no comments were marked as read.
980
+     *
981
+     * @param string $objectType
982
+     * @param string $objectId
983
+     * @param IUser $user
984
+     * @return \DateTime|null
985
+     * @since 9.0.0
986
+     */
987
+    public function getReadMark($objectType, $objectId, IUser $user) {
988
+        $qb = $this->dbConn->getQueryBuilder();
989
+        $resultStatement = $qb->select('marker_datetime')
990
+            ->from('comments_read_markers')
991
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
992
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
993
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
994
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
995
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
996
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
997
+            ->execute();
998
+
999
+        $data = $resultStatement->fetch();
1000
+        $resultStatement->closeCursor();
1001
+        if (!$data || is_null($data['marker_datetime'])) {
1002
+            return null;
1003
+        }
1004
+
1005
+        return new \DateTime($data['marker_datetime']);
1006
+    }
1007
+
1008
+    /**
1009
+     * deletes the read markers on the specified object
1010
+     *
1011
+     * @param string $objectType
1012
+     * @param string $objectId
1013
+     * @return bool
1014
+     * @since 9.0.0
1015
+     */
1016
+    public function deleteReadMarksOnObject($objectType, $objectId) {
1017
+        $this->checkRoleParameters('Object', $objectType, $objectId);
1018
+
1019
+        $qb = $this->dbConn->getQueryBuilder();
1020
+        $query = $qb->delete('comments_read_markers')
1021
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
1022
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
1023
+            ->setParameter('object_type', $objectType)
1024
+            ->setParameter('object_id', $objectId);
1025
+
1026
+        try {
1027
+            $affectedRows = $query->execute();
1028
+        } catch (DriverException $e) {
1029
+            $this->logger->logException($e, ['app' => 'core_comments']);
1030
+            return false;
1031
+        }
1032
+        return ($affectedRows > 0);
1033
+    }
1034
+
1035
+    /**
1036
+     * registers an Entity to the manager, so event notifications can be send
1037
+     * to consumers of the comments infrastructure
1038
+     *
1039
+     * @param \Closure $closure
1040
+     */
1041
+    public function registerEventHandler(\Closure $closure) {
1042
+        $this->eventHandlerClosures[] = $closure;
1043
+        $this->eventHandlers = [];
1044
+    }
1045
+
1046
+    /**
1047
+     * registers a method that resolves an ID to a display name for a given type
1048
+     *
1049
+     * @param string $type
1050
+     * @param \Closure $closure
1051
+     * @throws \OutOfBoundsException
1052
+     * @since 11.0.0
1053
+     *
1054
+     * Only one resolver shall be registered per type. Otherwise a
1055
+     * \OutOfBoundsException has to thrown.
1056
+     */
1057
+    public function registerDisplayNameResolver($type, \Closure $closure) {
1058
+        if (!is_string($type)) {
1059
+            throw new \InvalidArgumentException('String expected.');
1060
+        }
1061
+        if (isset($this->displayNameResolvers[$type])) {
1062
+            throw new \OutOfBoundsException('Displayname resolver for this type already registered');
1063
+        }
1064
+        $this->displayNameResolvers[$type] = $closure;
1065
+    }
1066
+
1067
+    /**
1068
+     * resolves a given ID of a given Type to a display name.
1069
+     *
1070
+     * @param string $type
1071
+     * @param string $id
1072
+     * @return string
1073
+     * @throws \OutOfBoundsException
1074
+     * @since 11.0.0
1075
+     *
1076
+     * If a provided type was not registered, an \OutOfBoundsException shall
1077
+     * be thrown. It is upon the resolver discretion what to return of the
1078
+     * provided ID is unknown. It must be ensured that a string is returned.
1079
+     */
1080
+    public function resolveDisplayName($type, $id) {
1081
+        if (!is_string($type)) {
1082
+            throw new \InvalidArgumentException('String expected.');
1083
+        }
1084
+        if (!isset($this->displayNameResolvers[$type])) {
1085
+            throw new \OutOfBoundsException('No Displayname resolver for this type registered');
1086
+        }
1087
+        return (string)$this->displayNameResolvers[$type]($id);
1088
+    }
1089
+
1090
+    /**
1091
+     * returns valid, registered entities
1092
+     *
1093
+     * @return \OCP\Comments\ICommentsEventHandler[]
1094
+     */
1095
+    private function getEventHandlers() {
1096
+        if (!empty($this->eventHandlers)) {
1097
+            return $this->eventHandlers;
1098
+        }
1099
+
1100
+        $this->eventHandlers = [];
1101
+        foreach ($this->eventHandlerClosures as $name => $closure) {
1102
+            $entity = $closure();
1103
+            if (!($entity instanceof ICommentsEventHandler)) {
1104
+                throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
1105
+            }
1106
+            $this->eventHandlers[$name] = $entity;
1107
+        }
1108
+
1109
+        return $this->eventHandlers;
1110
+    }
1111
+
1112
+    /**
1113
+     * sends notifications to the registered entities
1114
+     *
1115
+     * @param $eventType
1116
+     * @param IComment $comment
1117
+     */
1118
+    private function sendEvent($eventType, IComment $comment) {
1119
+        $entities = $this->getEventHandlers();
1120
+        $event = new CommentsEvent($eventType, $comment);
1121
+        foreach ($entities as $entity) {
1122
+            $entity->handle($event);
1123
+        }
1124
+    }
1125 1125
 }
Please login to merge, or discard this patch.
core/Application.php 1 patch
Indentation   +137 added lines, -137 removed lines patch added patch discarded remove patch
@@ -56,142 +56,142 @@
 block discarded – undo
56 56
  */
57 57
 class Application extends App {
58 58
 
59
-	public function __construct() {
60
-		parent::__construct('core');
61
-
62
-		$container = $this->getContainer();
63
-
64
-		$container->registerService('defaultMailAddress', function () {
65
-			return Util::getDefaultEmailAddress('lostpassword-noreply');
66
-		});
67
-
68
-		$server = $container->getServer();
69
-		/** @var IEventDispatcher $eventDispatcher */
70
-		$eventDispatcher = $server->query(IEventDispatcher::class);
71
-
72
-		$notificationManager = $server->getNotificationManager();
73
-		$notificationManager->registerNotifierService(RemoveLinkSharesNotifier::class);
74
-		$notificationManager->registerNotifierService(AuthenticationNotifier::class);
75
-
76
-		$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
77
-			function (GenericEvent $event) use ($container) {
78
-				/** @var MissingIndexInformation $subject */
79
-				$subject = $event->getSubject();
80
-
81
-				$schema = new SchemaWrapper($container->query(IDBConnection::class));
82
-
83
-				if ($schema->hasTable('share')) {
84
-					$table = $schema->getTable('share');
85
-
86
-					if (!$table->hasIndex('share_with_index')) {
87
-						$subject->addHintForMissingSubject($table->getName(), 'share_with_index');
88
-					}
89
-					if (!$table->hasIndex('parent_index')) {
90
-						$subject->addHintForMissingSubject($table->getName(), 'parent_index');
91
-					}
92
-					if (!$table->hasIndex('owner_index')) {
93
-						$subject->addHintForMissingSubject($table->getName(), 'owner_index');
94
-					}
95
-					if (!$table->hasIndex('initiator_index')) {
96
-						$subject->addHintForMissingSubject($table->getName(), 'initiator_index');
97
-					}
98
-				}
99
-
100
-				if ($schema->hasTable('filecache')) {
101
-					$table = $schema->getTable('filecache');
102
-
103
-					if (!$table->hasIndex('fs_mtime')) {
104
-						$subject->addHintForMissingSubject($table->getName(), 'fs_mtime');
105
-					}
106
-				}
107
-
108
-				if ($schema->hasTable('twofactor_providers')) {
109
-					$table = $schema->getTable('twofactor_providers');
110
-
111
-					if (!$table->hasIndex('twofactor_providers_uid')) {
112
-						$subject->addHintForMissingSubject($table->getName(), 'twofactor_providers_uid');
113
-					}
114
-				}
115
-
116
-				if ($schema->hasTable('login_flow_v2')) {
117
-					$table = $schema->getTable('login_flow_v2');
118
-
119
-					if (!$table->hasIndex('poll_token')) {
120
-						$subject->addHintForMissingSubject($table->getName(), 'poll_token');
121
-					}
122
-					if (!$table->hasIndex('login_token')) {
123
-						$subject->addHintForMissingSubject($table->getName(), 'login_token');
124
-					}
125
-					if (!$table->hasIndex('timestamp')) {
126
-						$subject->addHintForMissingSubject($table->getName(), 'timestamp');
127
-					}
128
-				}
129
-
130
-				if ($schema->hasTable('whats_new')) {
131
-					$table = $schema->getTable('whats_new');
132
-
133
-					if (!$table->hasIndex('version')) {
134
-						$subject->addHintForMissingSubject($table->getName(), 'version');
135
-					}
136
-				}
137
-
138
-				if ($schema->hasTable('cards')) {
139
-					$table = $schema->getTable('cards');
140
-
141
-					if (!$table->hasIndex('cards_abid')) {
142
-						$subject->addHintForMissingSubject($table->getName(), 'cards_abid');
143
-					}
144
-				}
145
-
146
-				if ($schema->hasTable('cards_properties')) {
147
-					$table = $schema->getTable('cards_properties');
148
-
149
-					if (!$table->hasIndex('cards_prop_abid')) {
150
-						$subject->addHintForMissingSubject($table->getName(), 'cards_prop_abid');
151
-					}
152
-				}
153
-
154
-				if ($schema->hasTable('calendarobjects_props')) {
155
-					$table = $schema->getTable('calendarobjects_props');
156
-
157
-					if (!$table->hasIndex('calendarobject_calid_index')) {
158
-						$subject->addHintForMissingSubject($table->getName(), 'calendarobject_calid_index');
159
-					}
160
-				}
161
-
162
-				if ($schema->hasTable('schedulingobjects')) {
163
-					$table = $schema->getTable('schedulingobjects');
164
-					if (!$table->hasIndex('schedulobj_principuri_index')) {
165
-						$subject->addHintForMissingSubject($table->getName(), 'schedulobj_principuri_index');
166
-					}
167
-				}
168
-			}
169
-		);
170
-
171
-		$eventDispatcher->addListener(IDBConnection::CHECK_MISSING_COLUMNS_EVENT,
172
-			function (GenericEvent $event) use ($container) {
173
-				/** @var MissingColumnInformation $subject */
174
-				$subject = $event->getSubject();
175
-
176
-				$schema = new SchemaWrapper($container->query(IDBConnection::class));
177
-
178
-				if ($schema->hasTable('comments')) {
179
-					$table = $schema->getTable('comments');
180
-
181
-					if (!$table->hasColumn('reference_id')) {
182
-						$subject->addHintForMissingColumn($table->getName(), 'reference_id');
183
-					}
184
-				}
185
-			}
186
-		);
187
-
188
-		$eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeActivityListener::class);
189
-		$eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeNotificationsListener::class);
190
-		$eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeEmailListener::class);
191
-		$eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeActivityListener::class);
192
-		$eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeNotificationsListener::class);
193
-		$eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeEmailListener::class);
194
-		$eventDispatcher->addServiceListener(UserDeletedEvent::class, UserDeletedStoreCleanupListener::class);
195
-	}
59
+    public function __construct() {
60
+        parent::__construct('core');
61
+
62
+        $container = $this->getContainer();
63
+
64
+        $container->registerService('defaultMailAddress', function () {
65
+            return Util::getDefaultEmailAddress('lostpassword-noreply');
66
+        });
67
+
68
+        $server = $container->getServer();
69
+        /** @var IEventDispatcher $eventDispatcher */
70
+        $eventDispatcher = $server->query(IEventDispatcher::class);
71
+
72
+        $notificationManager = $server->getNotificationManager();
73
+        $notificationManager->registerNotifierService(RemoveLinkSharesNotifier::class);
74
+        $notificationManager->registerNotifierService(AuthenticationNotifier::class);
75
+
76
+        $eventDispatcher->addListener(IDBConnection::CHECK_MISSING_INDEXES_EVENT,
77
+            function (GenericEvent $event) use ($container) {
78
+                /** @var MissingIndexInformation $subject */
79
+                $subject = $event->getSubject();
80
+
81
+                $schema = new SchemaWrapper($container->query(IDBConnection::class));
82
+
83
+                if ($schema->hasTable('share')) {
84
+                    $table = $schema->getTable('share');
85
+
86
+                    if (!$table->hasIndex('share_with_index')) {
87
+                        $subject->addHintForMissingSubject($table->getName(), 'share_with_index');
88
+                    }
89
+                    if (!$table->hasIndex('parent_index')) {
90
+                        $subject->addHintForMissingSubject($table->getName(), 'parent_index');
91
+                    }
92
+                    if (!$table->hasIndex('owner_index')) {
93
+                        $subject->addHintForMissingSubject($table->getName(), 'owner_index');
94
+                    }
95
+                    if (!$table->hasIndex('initiator_index')) {
96
+                        $subject->addHintForMissingSubject($table->getName(), 'initiator_index');
97
+                    }
98
+                }
99
+
100
+                if ($schema->hasTable('filecache')) {
101
+                    $table = $schema->getTable('filecache');
102
+
103
+                    if (!$table->hasIndex('fs_mtime')) {
104
+                        $subject->addHintForMissingSubject($table->getName(), 'fs_mtime');
105
+                    }
106
+                }
107
+
108
+                if ($schema->hasTable('twofactor_providers')) {
109
+                    $table = $schema->getTable('twofactor_providers');
110
+
111
+                    if (!$table->hasIndex('twofactor_providers_uid')) {
112
+                        $subject->addHintForMissingSubject($table->getName(), 'twofactor_providers_uid');
113
+                    }
114
+                }
115
+
116
+                if ($schema->hasTable('login_flow_v2')) {
117
+                    $table = $schema->getTable('login_flow_v2');
118
+
119
+                    if (!$table->hasIndex('poll_token')) {
120
+                        $subject->addHintForMissingSubject($table->getName(), 'poll_token');
121
+                    }
122
+                    if (!$table->hasIndex('login_token')) {
123
+                        $subject->addHintForMissingSubject($table->getName(), 'login_token');
124
+                    }
125
+                    if (!$table->hasIndex('timestamp')) {
126
+                        $subject->addHintForMissingSubject($table->getName(), 'timestamp');
127
+                    }
128
+                }
129
+
130
+                if ($schema->hasTable('whats_new')) {
131
+                    $table = $schema->getTable('whats_new');
132
+
133
+                    if (!$table->hasIndex('version')) {
134
+                        $subject->addHintForMissingSubject($table->getName(), 'version');
135
+                    }
136
+                }
137
+
138
+                if ($schema->hasTable('cards')) {
139
+                    $table = $schema->getTable('cards');
140
+
141
+                    if (!$table->hasIndex('cards_abid')) {
142
+                        $subject->addHintForMissingSubject($table->getName(), 'cards_abid');
143
+                    }
144
+                }
145
+
146
+                if ($schema->hasTable('cards_properties')) {
147
+                    $table = $schema->getTable('cards_properties');
148
+
149
+                    if (!$table->hasIndex('cards_prop_abid')) {
150
+                        $subject->addHintForMissingSubject($table->getName(), 'cards_prop_abid');
151
+                    }
152
+                }
153
+
154
+                if ($schema->hasTable('calendarobjects_props')) {
155
+                    $table = $schema->getTable('calendarobjects_props');
156
+
157
+                    if (!$table->hasIndex('calendarobject_calid_index')) {
158
+                        $subject->addHintForMissingSubject($table->getName(), 'calendarobject_calid_index');
159
+                    }
160
+                }
161
+
162
+                if ($schema->hasTable('schedulingobjects')) {
163
+                    $table = $schema->getTable('schedulingobjects');
164
+                    if (!$table->hasIndex('schedulobj_principuri_index')) {
165
+                        $subject->addHintForMissingSubject($table->getName(), 'schedulobj_principuri_index');
166
+                    }
167
+                }
168
+            }
169
+        );
170
+
171
+        $eventDispatcher->addListener(IDBConnection::CHECK_MISSING_COLUMNS_EVENT,
172
+            function (GenericEvent $event) use ($container) {
173
+                /** @var MissingColumnInformation $subject */
174
+                $subject = $event->getSubject();
175
+
176
+                $schema = new SchemaWrapper($container->query(IDBConnection::class));
177
+
178
+                if ($schema->hasTable('comments')) {
179
+                    $table = $schema->getTable('comments');
180
+
181
+                    if (!$table->hasColumn('reference_id')) {
182
+                        $subject->addHintForMissingColumn($table->getName(), 'reference_id');
183
+                    }
184
+                }
185
+            }
186
+        );
187
+
188
+        $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeActivityListener::class);
189
+        $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeNotificationsListener::class);
190
+        $eventDispatcher->addServiceListener(RemoteWipeStarted::class, RemoteWipeEmailListener::class);
191
+        $eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeActivityListener::class);
192
+        $eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeNotificationsListener::class);
193
+        $eventDispatcher->addServiceListener(RemoteWipeFinished::class, RemoteWipeEmailListener::class);
194
+        $eventDispatcher->addServiceListener(UserDeletedEvent::class, UserDeletedStoreCleanupListener::class);
195
+    }
196 196
 
197 197
 }
Please login to merge, or discard this patch.
core/Migrations/Version13000Date20170718121200.php 1 patch
Indentation   +894 added lines, -894 removed lines patch added patch discarded remove patch
@@ -34,899 +34,899 @@
 block discarded – undo
34 34
 
35 35
 class Version13000Date20170718121200 extends SimpleMigrationStep {
36 36
 
37
-	/**
38
-	 * @param IOutput $output
39
-	 * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
40
-	 * @param array $options
41
-	 * @return null|ISchemaWrapper
42
-	 * @since 13.0.0
43
-	 */
44
-	public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
45
-		/** @var ISchemaWrapper $schema */
46
-		$schema = $schemaClosure();
47
-
48
-		if (!$schema->hasTable('appconfig')) {
49
-			$table = $schema->createTable('appconfig');
50
-			$table->addColumn('appid', 'string', [
51
-				'notnull' => true,
52
-				'length' => 32,
53
-				'default' => '',
54
-			]);
55
-			$table->addColumn('configkey', 'string', [
56
-				'notnull' => true,
57
-				'length' => 64,
58
-				'default' => '',
59
-			]);
60
-			$table->addColumn('configvalue', 'text', [
61
-				'notnull' => false,
62
-			]);
63
-			$table->setPrimaryKey(['appid', 'configkey']);
64
-			$table->addIndex(['configkey'], 'appconfig_config_key_index');
65
-			$table->addIndex(['appid'], 'appconfig_appid_key');
66
-		}
67
-
68
-		if (!$schema->hasTable('storages')) {
69
-			$table = $schema->createTable('storages');
70
-			$table->addColumn('id', 'string', [
71
-				'notnull' => false,
72
-				'length' => 64,
73
-			]);
74
-			$table->addColumn('numeric_id', Type::BIGINT, [
75
-				'autoincrement' => true,
76
-				'notnull' => true,
77
-				'length' => 20,
78
-			]);
79
-			$table->addColumn('available', 'integer', [
80
-				'notnull' => true,
81
-				'default' => 1,
82
-			]);
83
-			$table->addColumn('last_checked', 'integer', [
84
-				'notnull' => false,
85
-			]);
86
-			$table->setPrimaryKey(['numeric_id']);
87
-			$table->addUniqueIndex(['id'], 'storages_id_index');
88
-		}
89
-
90
-		if (!$schema->hasTable('mounts')) {
91
-			$table = $schema->createTable('mounts');
92
-			$table->addColumn('id', 'integer', [
93
-				'autoincrement' => true,
94
-				'notnull' => true,
95
-				'length' => 4,
96
-			]);
97
-			$table->addColumn('storage_id', 'integer', [
98
-				'notnull' => true,
99
-			]);
100
-			$table->addColumn('root_id', 'integer', [
101
-				'notnull' => true,
102
-			]);
103
-			$table->addColumn('user_id', 'string', [
104
-				'notnull' => true,
105
-				'length' => 64,
106
-			]);
107
-			$table->addColumn('mount_point', 'string', [
108
-				'notnull' => true,
109
-				'length' => 4000,
110
-			]);
111
-			$table->addColumn('mount_id', 'integer', [
112
-				'notnull' => false,
113
-			]);
114
-			$table->setPrimaryKey(['id']);
115
-			$table->addIndex(['user_id'], 'mounts_user_index');
116
-			$table->addIndex(['storage_id'], 'mounts_storage_index');
117
-			$table->addIndex(['root_id'], 'mounts_root_index');
118
-			$table->addIndex(['mount_id'], 'mounts_mount_id_index');
119
-			$table->addUniqueIndex(['user_id', 'root_id'], 'mounts_user_root_index');
120
-		}
121
-
122
-		if (!$schema->hasTable('mimetypes')) {
123
-			$table = $schema->createTable('mimetypes');
124
-			$table->addColumn('id', Type::BIGINT, [
125
-				'autoincrement' => true,
126
-				'notnull' => true,
127
-				'length' => 20,
128
-			]);
129
-			$table->addColumn('mimetype', 'string', [
130
-				'notnull' => true,
131
-				'length' => 255,
132
-				'default' => '',
133
-			]);
134
-			$table->setPrimaryKey(['id']);
135
-			$table->addUniqueIndex(['mimetype'], 'mimetype_id_index');
136
-		}
137
-
138
-		if (!$schema->hasTable('filecache')) {
139
-			$table = $schema->createTable('filecache');
140
-			$table->addColumn('fileid', Type::BIGINT, [
141
-				'autoincrement' => true,
142
-				'notnull' => true,
143
-				'length' => 20,
144
-			]);
145
-			$table->addColumn('storage', Type::BIGINT, [
146
-				'notnull' => true,
147
-				'length' => 20,
148
-				'default' => 0,
149
-			]);
150
-			$table->addColumn('path', 'string', [
151
-				'notnull' => false,
152
-				'length' => 4000,
153
-			]);
154
-			$table->addColumn('path_hash', 'string', [
155
-				'notnull' => true,
156
-				'length' => 32,
157
-				'default' => '',
158
-			]);
159
-			$table->addColumn('parent', Type::BIGINT, [
160
-				'notnull' => true,
161
-				'length' => 20,
162
-				'default' => 0,
163
-			]);
164
-			$table->addColumn('name', 'string', [
165
-				'notnull' => false,
166
-				'length' => 250,
167
-			]);
168
-			$table->addColumn('mimetype', Type::BIGINT, [
169
-				'notnull' => true,
170
-				'length' => 20,
171
-				'default' => 0,
172
-			]);
173
-			$table->addColumn('mimepart', Type::BIGINT, [
174
-				'notnull' => true,
175
-				'length' => 20,
176
-				'default' => 0,
177
-			]);
178
-			$table->addColumn('size', 'bigint', [
179
-				'notnull' => true,
180
-				'length' => 8,
181
-				'default' => 0,
182
-			]);
183
-			$table->addColumn('mtime', Type::BIGINT, [
184
-				'notnull' => true,
185
-				'length' => 20,
186
-				'default' => 0,
187
-			]);
188
-			$table->addColumn('storage_mtime', Type::BIGINT, [
189
-				'notnull' => true,
190
-				'length' => 20,
191
-				'default' => 0,
192
-			]);
193
-			$table->addColumn('encrypted', 'integer', [
194
-				'notnull' => true,
195
-				'length' => 4,
196
-				'default' => 0,
197
-			]);
198
-			$table->addColumn('unencrypted_size', 'bigint', [
199
-				'notnull' => true,
200
-				'length' => 8,
201
-				'default' => 0,
202
-			]);
203
-			$table->addColumn('etag', 'string', [
204
-				'notnull' => false,
205
-				'length' => 40,
206
-			]);
207
-			$table->addColumn('permissions', 'integer', [
208
-				'notnull' => false,
209
-				'length' => 4,
210
-				'default' => 0,
211
-			]);
212
-			$table->addColumn('checksum', 'string', [
213
-				'notnull' => false,
214
-				'length' => 255,
215
-			]);
216
-			$table->setPrimaryKey(['fileid']);
217
-			$table->addUniqueIndex(['storage', 'path_hash'], 'fs_storage_path_hash');
218
-			$table->addIndex(['parent', 'name'], 'fs_parent_name_hash');
219
-			$table->addIndex(['storage', 'mimetype'], 'fs_storage_mimetype');
220
-			$table->addIndex(['storage', 'mimepart'], 'fs_storage_mimepart');
221
-			$table->addIndex(['storage', 'size', 'fileid'], 'fs_storage_size');
222
-			$table->addIndex(['mtime'], 'fs_mtime');
223
-		}
224
-
225
-		if (!$schema->hasTable('group_user')) {
226
-			$table = $schema->createTable('group_user');
227
-			$table->addColumn('gid', 'string', [
228
-				'notnull' => true,
229
-				'length' => 64,
230
-				'default' => '',
231
-			]);
232
-			$table->addColumn('uid', 'string', [
233
-				'notnull' => true,
234
-				'length' => 64,
235
-				'default' => '',
236
-			]);
237
-			$table->setPrimaryKey(['gid', 'uid']);
238
-			$table->addIndex(['uid'], 'gu_uid_index');
239
-		}
240
-
241
-		if (!$schema->hasTable('group_admin')) {
242
-			$table = $schema->createTable('group_admin');
243
-			$table->addColumn('gid', 'string', [
244
-				'notnull' => true,
245
-				'length' => 64,
246
-				'default' => '',
247
-			]);
248
-			$table->addColumn('uid', 'string', [
249
-				'notnull' => true,
250
-				'length' => 64,
251
-				'default' => '',
252
-			]);
253
-			$table->setPrimaryKey(['gid', 'uid']);
254
-			$table->addIndex(['uid'], 'group_admin_uid');
255
-		}
256
-
257
-		if (!$schema->hasTable('groups')) {
258
-			$table = $schema->createTable('groups');
259
-			$table->addColumn('gid', 'string', [
260
-				'notnull' => true,
261
-				'length' => 64,
262
-				'default' => '',
263
-			]);
264
-			$table->setPrimaryKey(['gid']);
265
-		}
266
-
267
-		if (!$schema->hasTable('preferences')) {
268
-			$table = $schema->createTable('preferences');
269
-			$table->addColumn('userid', 'string', [
270
-				'notnull' => true,
271
-				'length' => 64,
272
-				'default' => '',
273
-			]);
274
-			$table->addColumn('appid', 'string', [
275
-				'notnull' => true,
276
-				'length' => 32,
277
-				'default' => '',
278
-			]);
279
-			$table->addColumn('configkey', 'string', [
280
-				'notnull' => true,
281
-				'length' => 64,
282
-				'default' => '',
283
-			]);
284
-			$table->addColumn('configvalue', 'text', [
285
-				'notnull' => false,
286
-			]);
287
-			$table->setPrimaryKey(['userid', 'appid', 'configkey']);
288
-		}
289
-
290
-		if (!$schema->hasTable('properties')) {
291
-			$table = $schema->createTable('properties');
292
-			$table->addColumn('id', 'integer', [
293
-				'autoincrement' => true,
294
-				'notnull' => true,
295
-				'length' => 4,
296
-			]);
297
-			$table->addColumn('userid', 'string', [
298
-				'notnull' => true,
299
-				'length' => 64,
300
-				'default' => '',
301
-			]);
302
-			$table->addColumn('propertypath', 'string', [
303
-				'notnull' => true,
304
-				'length' => 255,
305
-				'default' => '',
306
-			]);
307
-			$table->addColumn('propertyname', 'string', [
308
-				'notnull' => true,
309
-				'length' => 255,
310
-				'default' => '',
311
-			]);
312
-			$table->addColumn('propertyvalue', 'text', [
313
-				'notnull' => true,
314
-			]);
315
-			$table->setPrimaryKey(['id']);
316
-			$table->addIndex(['userid'], 'property_index');
317
-		}
318
-
319
-		if (!$schema->hasTable('share')) {
320
-			$table = $schema->createTable('share');
321
-			$table->addColumn('id', 'integer', [
322
-				'autoincrement' => true,
323
-				'notnull' => true,
324
-				'length' => 4,
325
-			]);
326
-			$table->addColumn('share_type', 'smallint', [
327
-				'notnull' => true,
328
-				'length' => 1,
329
-				'default' => 0,
330
-			]);
331
-			$table->addColumn('share_with', 'string', [
332
-				'notnull' => false,
333
-				'length' => 255,
334
-			]);
335
-			$table->addColumn('password', 'string', [
336
-				'notnull' => false,
337
-				'length' => 255,
338
-			]);
339
-			$table->addColumn('uid_owner', 'string', [
340
-				'notnull' => true,
341
-				'length' => 64,
342
-				'default' => '',
343
-			]);
344
-			$table->addColumn('uid_initiator', 'string', [
345
-				'notnull' => false,
346
-				'length' => 64,
347
-			]);
348
-			$table->addColumn('parent', 'integer', [
349
-				'notnull' => false,
350
-				'length' => 4,
351
-			]);
352
-			$table->addColumn('item_type', 'string', [
353
-				'notnull' => true,
354
-				'length' => 64,
355
-				'default' => '',
356
-			]);
357
-			$table->addColumn('item_source', 'string', [
358
-				'notnull' => false,
359
-				'length' => 255,
360
-			]);
361
-			$table->addColumn('item_target', 'string', [
362
-				'notnull' => false,
363
-				'length' => 255,
364
-			]);
365
-			$table->addColumn('file_source', 'integer', [
366
-				'notnull' => false,
367
-				'length' => 4,
368
-			]);
369
-			$table->addColumn('file_target', 'string', [
370
-				'notnull' => false,
371
-				'length' => 512,
372
-			]);
373
-			$table->addColumn('permissions', 'smallint', [
374
-				'notnull' => true,
375
-				'length' => 1,
376
-				'default' => 0,
377
-			]);
378
-			$table->addColumn('stime', 'bigint', [
379
-				'notnull' => true,
380
-				'length' => 8,
381
-				'default' => 0,
382
-			]);
383
-			$table->addColumn('accepted', 'smallint', [
384
-				'notnull' => true,
385
-				'length' => 1,
386
-				'default' => 0,
387
-			]);
388
-			$table->addColumn('expiration', 'datetime', [
389
-				'notnull' => false,
390
-			]);
391
-			$table->addColumn('token', 'string', [
392
-				'notnull' => false,
393
-				'length' => 32,
394
-			]);
395
-			$table->addColumn('mail_send', 'smallint', [
396
-				'notnull' => true,
397
-				'length' => 1,
398
-				'default' => 0,
399
-			]);
400
-			$table->addColumn('share_name', 'string', [
401
-				'notnull' => false,
402
-				'length' => 64,
403
-			]);
404
-			$table->setPrimaryKey(['id']);
405
-			$table->addIndex(['item_type', 'share_type'], 'item_share_type_index');
406
-			$table->addIndex(['file_source'], 'file_source_index');
407
-			$table->addIndex(['token'], 'token_index');
408
-			$table->addIndex(['share_with'], 'share_with_index');
409
-			$table->addIndex(['parent'], 'parent_index');
410
-			$table->addIndex(['uid_owner'], 'owner_index');
411
-			$table->addIndex(['uid_initiator'], 'initiator_index');
412
-		}
413
-
414
-		if (!$schema->hasTable('jobs')) {
415
-			$table = $schema->createTable('jobs');
416
-			$table->addColumn('id', 'integer', [
417
-				'autoincrement' => true,
418
-				'notnull' => true,
419
-				'length' => 4,
420
-				'unsigned' => true,
421
-			]);
422
-			$table->addColumn('class', 'string', [
423
-				'notnull' => true,
424
-				'length' => 255,
425
-				'default' => '',
426
-			]);
427
-			$table->addColumn('argument', 'string', [
428
-				'notnull' => true,
429
-				'length' => 4000,
430
-				'default' => '',
431
-			]);
432
-			$table->addColumn('last_run', 'integer', [
433
-				'notnull' => false,
434
-				'default' => 0,
435
-			]);
436
-			$table->addColumn('last_checked', 'integer', [
437
-				'notnull' => false,
438
-				'default' => 0,
439
-			]);
440
-			$table->addColumn('reserved_at', 'integer', [
441
-				'notnull' => false,
442
-				'default' => 0,
443
-			]);
444
-			$table->addColumn('execution_duration', 'integer', [
445
-				'notnull' => true,
446
-				'default' => 0,
447
-			]);
448
-			$table->setPrimaryKey(['id']);
449
-			$table->addIndex(['class'], 'job_class_index');
450
-		}
451
-
452
-		if (!$schema->hasTable('users')) {
453
-			$table = $schema->createTable('users');
454
-			$table->addColumn('uid', 'string', [
455
-				'notnull' => true,
456
-				'length' => 64,
457
-				'default' => '',
458
-			]);
459
-			$table->addColumn('displayname', 'string', [
460
-				'notnull' => false,
461
-				'length' => 64,
462
-			]);
463
-			$table->addColumn('password', 'string', [
464
-				'notnull' => true,
465
-				'length' => 255,
466
-				'default' => '',
467
-			]);
468
-			$table->setPrimaryKey(['uid']);
469
-		}
470
-
471
-		if (!$schema->hasTable('authtoken')) {
472
-			$table = $schema->createTable('authtoken');
473
-			$table->addColumn('id', 'integer', [
474
-				'autoincrement' => true,
475
-				'notnull' => true,
476
-				'length' => 4,
477
-				'unsigned' => true,
478
-			]);
479
-			$table->addColumn('uid', 'string', [
480
-				'notnull' => true,
481
-				'length' => 64,
482
-				'default' => '',
483
-			]);
484
-			$table->addColumn('login_name', 'string', [
485
-				'notnull' => true,
486
-				'length' => 64,
487
-				'default' => '',
488
-			]);
489
-			$table->addColumn('password', 'text', [
490
-				'notnull' => false,
491
-			]);
492
-			$table->addColumn('name', 'text', [
493
-				'notnull' => true,
494
-				'default' => '',
495
-			]);
496
-			$table->addColumn('token', 'string', [
497
-				'notnull' => true,
498
-				'length' => 200,
499
-				'default' => '',
500
-			]);
501
-			$table->addColumn('type', 'smallint', [
502
-				'notnull' => true,
503
-				'length' => 2,
504
-				'default' => 0,
505
-				'unsigned' => true,
506
-			]);
507
-			$table->addColumn('remember', 'smallint', [
508
-				'notnull' => true,
509
-				'length' => 1,
510
-				'default' => 0,
511
-				'unsigned' => true,
512
-			]);
513
-			$table->addColumn('last_activity', 'integer', [
514
-				'notnull' => true,
515
-				'length' => 4,
516
-				'default' => 0,
517
-				'unsigned' => true,
518
-			]);
519
-			$table->addColumn('last_check', 'integer', [
520
-				'notnull' => true,
521
-				'length' => 4,
522
-				'default' => 0,
523
-				'unsigned' => true,
524
-			]);
525
-			$table->addColumn('scope', 'text', [
526
-				'notnull' => false,
527
-			]);
528
-			$table->setPrimaryKey(['id']);
529
-			$table->addUniqueIndex(['token'], 'authtoken_token_index');
530
-			$table->addIndex(['last_activity'], 'authtoken_last_activity_idx');
531
-		}
532
-
533
-		if (!$schema->hasTable('bruteforce_attempts')) {
534
-			$table = $schema->createTable('bruteforce_attempts');
535
-			$table->addColumn('id', 'integer', [
536
-				'autoincrement' => true,
537
-				'notnull' => true,
538
-				'length' => 4,
539
-				'unsigned' => true,
540
-			]);
541
-			$table->addColumn('action', 'string', [
542
-				'notnull' => true,
543
-				'length' => 64,
544
-				'default' => '',
545
-			]);
546
-			$table->addColumn('occurred', 'integer', [
547
-				'notnull' => true,
548
-				'length' => 4,
549
-				'default' => 0,
550
-				'unsigned' => true,
551
-			]);
552
-			$table->addColumn('ip', 'string', [
553
-				'notnull' => true,
554
-				'length' => 255,
555
-				'default' => '',
556
-			]);
557
-			$table->addColumn('subnet', 'string', [
558
-				'notnull' => true,
559
-				'length' => 255,
560
-				'default' => '',
561
-			]);
562
-			$table->addColumn('metadata', 'string', [
563
-				'notnull' => true,
564
-				'length' => 255,
565
-				'default' => '',
566
-			]);
567
-			$table->setPrimaryKey(['id']);
568
-			$table->addIndex(['ip'], 'bruteforce_attempts_ip');
569
-			$table->addIndex(['subnet'], 'bruteforce_attempts_subnet');
570
-		}
571
-
572
-		if (!$schema->hasTable('vcategory')) {
573
-			$table = $schema->createTable('vcategory');
574
-			$table->addColumn('id', 'integer', [
575
-				'autoincrement' => true,
576
-				'notnull' => true,
577
-				'length' => 4,
578
-				'unsigned' => true,
579
-			]);
580
-			$table->addColumn('uid', 'string', [
581
-				'notnull' => true,
582
-				'length' => 64,
583
-				'default' => '',
584
-			]);
585
-			$table->addColumn('type', 'string', [
586
-				'notnull' => true,
587
-				'length' => 64,
588
-				'default' => '',
589
-			]);
590
-			$table->addColumn('category', 'string', [
591
-				'notnull' => true,
592
-				'length' => 255,
593
-				'default' => '',
594
-			]);
595
-			$table->setPrimaryKey(['id']);
596
-			$table->addIndex(['uid'], 'uid_index');
597
-			$table->addIndex(['type'], 'type_index');
598
-			$table->addIndex(['category'], 'category_index');
599
-		}
600
-
601
-		if (!$schema->hasTable('vcategory_to_object')) {
602
-			$table = $schema->createTable('vcategory_to_object');
603
-			$table->addColumn('objid', 'integer', [
604
-				'notnull' => true,
605
-				'length' => 4,
606
-				'default' => 0,
607
-				'unsigned' => true,
608
-			]);
609
-			$table->addColumn('categoryid', 'integer', [
610
-				'notnull' => true,
611
-				'length' => 4,
612
-				'default' => 0,
613
-				'unsigned' => true,
614
-			]);
615
-			$table->addColumn('type', 'string', [
616
-				'notnull' => true,
617
-				'length' => 64,
618
-				'default' => '',
619
-			]);
620
-			$table->setPrimaryKey(['categoryid', 'objid', 'type']);
621
-			$table->addIndex(['objid', 'type'], 'vcategory_objectd_index');
622
-		}
623
-
624
-		if (!$schema->hasTable('systemtag')) {
625
-			$table = $schema->createTable('systemtag');
626
-			$table->addColumn('id', 'integer', [
627
-				'autoincrement' => true,
628
-				'notnull' => true,
629
-				'length' => 4,
630
-				'unsigned' => true,
631
-			]);
632
-			$table->addColumn('name', 'string', [
633
-				'notnull' => true,
634
-				'length' => 64,
635
-				'default' => '',
636
-			]);
637
-			$table->addColumn('visibility', 'smallint', [
638
-				'notnull' => true,
639
-				'length' => 1,
640
-				'default' => 1,
641
-			]);
642
-			$table->addColumn('editable', 'smallint', [
643
-				'notnull' => true,
644
-				'length' => 1,
645
-				'default' => 1,
646
-			]);
647
-			$table->setPrimaryKey(['id']);
648
-			$table->addUniqueIndex(['name', 'visibility', 'editable'], 'tag_ident');
649
-		}
650
-
651
-		if (!$schema->hasTable('systemtag_object_mapping')) {
652
-			$table = $schema->createTable('systemtag_object_mapping');
653
-			$table->addColumn('objectid', 'string', [
654
-				'notnull' => true,
655
-				'length' => 64,
656
-				'default' => '',
657
-			]);
658
-			$table->addColumn('objecttype', 'string', [
659
-				'notnull' => true,
660
-				'length' => 64,
661
-				'default' => '',
662
-			]);
663
-			$table->addColumn('systemtagid', 'integer', [
664
-				'notnull' => true,
665
-				'length' => 4,
666
-				'default' => 0,
667
-				'unsigned' => true,
668
-			]);
669
-			$table->addUniqueIndex(['objecttype', 'objectid', 'systemtagid'], 'mapping');
670
-		}
671
-
672
-		if (!$schema->hasTable('systemtag_group')) {
673
-			$table = $schema->createTable('systemtag_group');
674
-			$table->addColumn('systemtagid', 'integer', [
675
-				'notnull' => true,
676
-				'length' => 4,
677
-				'default' => 0,
678
-				'unsigned' => true,
679
-			]);
680
-			$table->addColumn('gid', 'string', [
681
-				'notnull' => true,
682
-			]);
683
-			$table->setPrimaryKey(['gid', 'systemtagid']);
684
-		}
685
-
686
-		if (!$schema->hasTable('file_locks')) {
687
-			$table = $schema->createTable('file_locks');
688
-			$table->addColumn('id', 'integer', [
689
-				'autoincrement' => true,
690
-				'notnull' => true,
691
-				'length' => 4,
692
-				'unsigned' => true,
693
-			]);
694
-			$table->addColumn('lock', 'integer', [
695
-				'notnull' => true,
696
-				'length' => 4,
697
-				'default' => 0,
698
-			]);
699
-			$table->addColumn('key', 'string', [
700
-				'notnull' => true,
701
-				'length' => 64,
702
-			]);
703
-			$table->addColumn('ttl', 'integer', [
704
-				'notnull' => true,
705
-				'length' => 4,
706
-				'default' => -1,
707
-			]);
708
-			$table->setPrimaryKey(['id']);
709
-			$table->addUniqueIndex(['key'], 'lock_key_index');
710
-			$table->addIndex(['ttl'], 'lock_ttl_index');
711
-		}
712
-
713
-		if (!$schema->hasTable('comments')) {
714
-			$table = $schema->createTable('comments');
715
-			$table->addColumn('id', 'integer', [
716
-				'autoincrement' => true,
717
-				'notnull' => true,
718
-				'length' => 4,
719
-				'unsigned' => true,
720
-			]);
721
-			$table->addColumn('parent_id', 'integer', [
722
-				'notnull' => true,
723
-				'length' => 4,
724
-				'default' => 0,
725
-				'unsigned' => true,
726
-			]);
727
-			$table->addColumn('topmost_parent_id', 'integer', [
728
-				'notnull' => true,
729
-				'length' => 4,
730
-				'default' => 0,
731
-				'unsigned' => true,
732
-			]);
733
-			$table->addColumn('children_count', 'integer', [
734
-				'notnull' => true,
735
-				'length' => 4,
736
-				'default' => 0,
737
-				'unsigned' => true,
738
-			]);
739
-			$table->addColumn('actor_type', 'string', [
740
-				'notnull' => true,
741
-				'length' => 64,
742
-				'default' => '',
743
-			]);
744
-			$table->addColumn('actor_id', 'string', [
745
-				'notnull' => true,
746
-				'length' => 64,
747
-				'default' => '',
748
-			]);
749
-			$table->addColumn('message', 'text', [
750
-				'notnull' => false,
751
-			]);
752
-			$table->addColumn('verb', 'string', [
753
-				'notnull' => false,
754
-				'length' => 64,
755
-			]);
756
-			$table->addColumn('creation_timestamp', 'datetime', [
757
-				'notnull' => false,
758
-			]);
759
-			$table->addColumn('latest_child_timestamp', 'datetime', [
760
-				'notnull' => false,
761
-			]);
762
-			$table->addColumn('object_type', 'string', [
763
-				'notnull' => true,
764
-				'length' => 64,
765
-				'default' => '',
766
-			]);
767
-			$table->addColumn('object_id', 'string', [
768
-				'notnull' => true,
769
-				'length' => 64,
770
-				'default' => '',
771
-			]);
772
-			$table->addColumn('reference_id', 'string', [
773
-				'notnull' => false,
774
-				'length' => 64,
775
-			]);
776
-			$table->setPrimaryKey(['id']);
777
-			$table->addIndex(['parent_id'], 'comments_parent_id_index');
778
-			$table->addIndex(['topmost_parent_id'], 'comments_topmost_parent_id_idx');
779
-			$table->addIndex(['object_type', 'object_id', 'creation_timestamp'], 'comments_object_index');
780
-			$table->addIndex(['actor_type', 'actor_id'], 'comments_actor_index');
781
-		}
782
-
783
-		if (!$schema->hasTable('comments_read_markers')) {
784
-			$table = $schema->createTable('comments_read_markers');
785
-			$table->addColumn('user_id', 'string', [
786
-				'notnull' => true,
787
-				'length' => 64,
788
-				'default' => '',
789
-			]);
790
-			$table->addColumn('marker_datetime', 'datetime', [
791
-				'notnull' => false,
792
-			]);
793
-			$table->addColumn('object_type', 'string', [
794
-				'notnull' => true,
795
-				'length' => 64,
796
-				'default' => '',
797
-			]);
798
-			$table->addColumn('object_id', 'string', [
799
-				'notnull' => true,
800
-				'length' => 64,
801
-				'default' => '',
802
-			]);
803
-			$table->addIndex(['object_type', 'object_id'], 'comments_marker_object_index');
804
-			$table->addUniqueIndex(['user_id', 'object_type', 'object_id'], 'comments_marker_index');
805
-		}
806
-
807
-		if (!$schema->hasTable('credentials')) {
808
-			$table = $schema->createTable('credentials');
809
-			$table->addColumn('user', 'string', [
810
-				'notnull' => true,
811
-				'length' => 64,
812
-			]);
813
-			$table->addColumn('identifier', 'string', [
814
-				'notnull' => true,
815
-				'length' => 64,
816
-			]);
817
-			$table->addColumn('credentials', 'text', [
818
-				'notnull' => false,
819
-			]);
820
-			$table->setPrimaryKey(['user', 'identifier']);
821
-			$table->addIndex(['user'], 'credentials_user');
822
-		}
823
-
824
-		if (!$schema->hasTable('admin_sections')) {
825
-			$table = $schema->createTable('admin_sections');
826
-			$table->addColumn('id', 'string', [
827
-				'notnull' => true,
828
-				'length' => 64,
829
-			]);
830
-			$table->addColumn('class', 'string', [
831
-				'notnull' => true,
832
-				'length' => 255,
833
-				'default' => '',
834
-			]);
835
-			$table->addColumn('priority', 'smallint', [
836
-				'notnull' => true,
837
-				'length' => 1,
838
-				'default' => 0,
839
-			]);
840
-			$table->setPrimaryKey(['id']);
841
-			$table->addUniqueIndex(['class'], 'admin_sections_class');
842
-		}
843
-
844
-		if (!$schema->hasTable('admin_settings')) {
845
-			$table = $schema->createTable('admin_settings');
846
-			$table->addColumn('id', 'integer', [
847
-				'autoincrement' => true,
848
-				'notnull' => true,
849
-				'length' => 4,
850
-			]);
851
-			$table->addColumn('class', 'string', [
852
-				'notnull' => true,
853
-				'length' => 255,
854
-				'default' => '',
855
-			]);
856
-			$table->addColumn('section', 'string', [
857
-				'notnull' => false,
858
-				'length' => 64,
859
-			]);
860
-			$table->addColumn('priority', 'smallint', [
861
-				'notnull' => true,
862
-				'length' => 1,
863
-				'default' => 0,
864
-			]);
865
-			$table->setPrimaryKey(['id']);
866
-			$table->addUniqueIndex(['class'], 'admin_settings_class');
867
-			$table->addIndex(['section'], 'admin_settings_section');
868
-		}
869
-
870
-		if (!$schema->hasTable('personal_sections')) {
871
-			$table = $schema->createTable('personal_sections');
872
-			$table->addColumn('id', 'string', [
873
-				'notnull' => true,
874
-				'length' => 64,
875
-			]);
876
-			$table->addColumn('class', 'string', [
877
-				'notnull' => true,
878
-				'length' => 255,
879
-				'default' => '',
880
-			]);
881
-			$table->addColumn('priority', 'smallint', [
882
-				'notnull' => true,
883
-				'length' => 1,
884
-				'default' => 0,
885
-			]);
886
-			$table->setPrimaryKey(['id']);
887
-			$table->addUniqueIndex(['class'], 'personal_sections_class');
888
-		}
889
-
890
-		if (!$schema->hasTable('personal_settings')) {
891
-			$table = $schema->createTable('personal_settings');
892
-			$table->addColumn('id', 'integer', [
893
-				'autoincrement' => true,
894
-				'notnull' => true,
895
-				'length' => 4,
896
-			]);
897
-			$table->addColumn('class', 'string', [
898
-				'notnull' => true,
899
-				'length' => 255,
900
-				'default' => '',
901
-			]);
902
-			$table->addColumn('section', 'string', [
903
-				'notnull' => false,
904
-				'length' => 64,
905
-			]);
906
-			$table->addColumn('priority', 'smallint', [
907
-				'notnull' => true,
908
-				'length' => 1,
909
-				'default' => 0,
910
-			]);
911
-			$table->setPrimaryKey(['id']);
912
-			$table->addUniqueIndex(['class'], 'personal_settings_class');
913
-			$table->addIndex(['section'], 'personal_settings_section');
914
-		}
915
-
916
-		if (!$schema->hasTable('accounts')) {
917
-			$table = $schema->createTable('accounts');
918
-			$table->addColumn('uid', 'string', [
919
-				'notnull' => true,
920
-				'length' => 64,
921
-				'default' => '',
922
-			]);
923
-			$table->addColumn('data', 'text', [
924
-				'notnull' => true,
925
-				'default' => '',
926
-			]);
927
-			$table->setPrimaryKey(['uid']);
928
-		}
929
-		return $schema;
930
-	}
37
+    /**
38
+     * @param IOutput $output
39
+     * @param \Closure $schemaClosure The `\Closure` returns a `ISchemaWrapper`
40
+     * @param array $options
41
+     * @return null|ISchemaWrapper
42
+     * @since 13.0.0
43
+     */
44
+    public function changeSchema(IOutput $output, \Closure $schemaClosure, array $options) {
45
+        /** @var ISchemaWrapper $schema */
46
+        $schema = $schemaClosure();
47
+
48
+        if (!$schema->hasTable('appconfig')) {
49
+            $table = $schema->createTable('appconfig');
50
+            $table->addColumn('appid', 'string', [
51
+                'notnull' => true,
52
+                'length' => 32,
53
+                'default' => '',
54
+            ]);
55
+            $table->addColumn('configkey', 'string', [
56
+                'notnull' => true,
57
+                'length' => 64,
58
+                'default' => '',
59
+            ]);
60
+            $table->addColumn('configvalue', 'text', [
61
+                'notnull' => false,
62
+            ]);
63
+            $table->setPrimaryKey(['appid', 'configkey']);
64
+            $table->addIndex(['configkey'], 'appconfig_config_key_index');
65
+            $table->addIndex(['appid'], 'appconfig_appid_key');
66
+        }
67
+
68
+        if (!$schema->hasTable('storages')) {
69
+            $table = $schema->createTable('storages');
70
+            $table->addColumn('id', 'string', [
71
+                'notnull' => false,
72
+                'length' => 64,
73
+            ]);
74
+            $table->addColumn('numeric_id', Type::BIGINT, [
75
+                'autoincrement' => true,
76
+                'notnull' => true,
77
+                'length' => 20,
78
+            ]);
79
+            $table->addColumn('available', 'integer', [
80
+                'notnull' => true,
81
+                'default' => 1,
82
+            ]);
83
+            $table->addColumn('last_checked', 'integer', [
84
+                'notnull' => false,
85
+            ]);
86
+            $table->setPrimaryKey(['numeric_id']);
87
+            $table->addUniqueIndex(['id'], 'storages_id_index');
88
+        }
89
+
90
+        if (!$schema->hasTable('mounts')) {
91
+            $table = $schema->createTable('mounts');
92
+            $table->addColumn('id', 'integer', [
93
+                'autoincrement' => true,
94
+                'notnull' => true,
95
+                'length' => 4,
96
+            ]);
97
+            $table->addColumn('storage_id', 'integer', [
98
+                'notnull' => true,
99
+            ]);
100
+            $table->addColumn('root_id', 'integer', [
101
+                'notnull' => true,
102
+            ]);
103
+            $table->addColumn('user_id', 'string', [
104
+                'notnull' => true,
105
+                'length' => 64,
106
+            ]);
107
+            $table->addColumn('mount_point', 'string', [
108
+                'notnull' => true,
109
+                'length' => 4000,
110
+            ]);
111
+            $table->addColumn('mount_id', 'integer', [
112
+                'notnull' => false,
113
+            ]);
114
+            $table->setPrimaryKey(['id']);
115
+            $table->addIndex(['user_id'], 'mounts_user_index');
116
+            $table->addIndex(['storage_id'], 'mounts_storage_index');
117
+            $table->addIndex(['root_id'], 'mounts_root_index');
118
+            $table->addIndex(['mount_id'], 'mounts_mount_id_index');
119
+            $table->addUniqueIndex(['user_id', 'root_id'], 'mounts_user_root_index');
120
+        }
121
+
122
+        if (!$schema->hasTable('mimetypes')) {
123
+            $table = $schema->createTable('mimetypes');
124
+            $table->addColumn('id', Type::BIGINT, [
125
+                'autoincrement' => true,
126
+                'notnull' => true,
127
+                'length' => 20,
128
+            ]);
129
+            $table->addColumn('mimetype', 'string', [
130
+                'notnull' => true,
131
+                'length' => 255,
132
+                'default' => '',
133
+            ]);
134
+            $table->setPrimaryKey(['id']);
135
+            $table->addUniqueIndex(['mimetype'], 'mimetype_id_index');
136
+        }
137
+
138
+        if (!$schema->hasTable('filecache')) {
139
+            $table = $schema->createTable('filecache');
140
+            $table->addColumn('fileid', Type::BIGINT, [
141
+                'autoincrement' => true,
142
+                'notnull' => true,
143
+                'length' => 20,
144
+            ]);
145
+            $table->addColumn('storage', Type::BIGINT, [
146
+                'notnull' => true,
147
+                'length' => 20,
148
+                'default' => 0,
149
+            ]);
150
+            $table->addColumn('path', 'string', [
151
+                'notnull' => false,
152
+                'length' => 4000,
153
+            ]);
154
+            $table->addColumn('path_hash', 'string', [
155
+                'notnull' => true,
156
+                'length' => 32,
157
+                'default' => '',
158
+            ]);
159
+            $table->addColumn('parent', Type::BIGINT, [
160
+                'notnull' => true,
161
+                'length' => 20,
162
+                'default' => 0,
163
+            ]);
164
+            $table->addColumn('name', 'string', [
165
+                'notnull' => false,
166
+                'length' => 250,
167
+            ]);
168
+            $table->addColumn('mimetype', Type::BIGINT, [
169
+                'notnull' => true,
170
+                'length' => 20,
171
+                'default' => 0,
172
+            ]);
173
+            $table->addColumn('mimepart', Type::BIGINT, [
174
+                'notnull' => true,
175
+                'length' => 20,
176
+                'default' => 0,
177
+            ]);
178
+            $table->addColumn('size', 'bigint', [
179
+                'notnull' => true,
180
+                'length' => 8,
181
+                'default' => 0,
182
+            ]);
183
+            $table->addColumn('mtime', Type::BIGINT, [
184
+                'notnull' => true,
185
+                'length' => 20,
186
+                'default' => 0,
187
+            ]);
188
+            $table->addColumn('storage_mtime', Type::BIGINT, [
189
+                'notnull' => true,
190
+                'length' => 20,
191
+                'default' => 0,
192
+            ]);
193
+            $table->addColumn('encrypted', 'integer', [
194
+                'notnull' => true,
195
+                'length' => 4,
196
+                'default' => 0,
197
+            ]);
198
+            $table->addColumn('unencrypted_size', 'bigint', [
199
+                'notnull' => true,
200
+                'length' => 8,
201
+                'default' => 0,
202
+            ]);
203
+            $table->addColumn('etag', 'string', [
204
+                'notnull' => false,
205
+                'length' => 40,
206
+            ]);
207
+            $table->addColumn('permissions', 'integer', [
208
+                'notnull' => false,
209
+                'length' => 4,
210
+                'default' => 0,
211
+            ]);
212
+            $table->addColumn('checksum', 'string', [
213
+                'notnull' => false,
214
+                'length' => 255,
215
+            ]);
216
+            $table->setPrimaryKey(['fileid']);
217
+            $table->addUniqueIndex(['storage', 'path_hash'], 'fs_storage_path_hash');
218
+            $table->addIndex(['parent', 'name'], 'fs_parent_name_hash');
219
+            $table->addIndex(['storage', 'mimetype'], 'fs_storage_mimetype');
220
+            $table->addIndex(['storage', 'mimepart'], 'fs_storage_mimepart');
221
+            $table->addIndex(['storage', 'size', 'fileid'], 'fs_storage_size');
222
+            $table->addIndex(['mtime'], 'fs_mtime');
223
+        }
224
+
225
+        if (!$schema->hasTable('group_user')) {
226
+            $table = $schema->createTable('group_user');
227
+            $table->addColumn('gid', 'string', [
228
+                'notnull' => true,
229
+                'length' => 64,
230
+                'default' => '',
231
+            ]);
232
+            $table->addColumn('uid', 'string', [
233
+                'notnull' => true,
234
+                'length' => 64,
235
+                'default' => '',
236
+            ]);
237
+            $table->setPrimaryKey(['gid', 'uid']);
238
+            $table->addIndex(['uid'], 'gu_uid_index');
239
+        }
240
+
241
+        if (!$schema->hasTable('group_admin')) {
242
+            $table = $schema->createTable('group_admin');
243
+            $table->addColumn('gid', 'string', [
244
+                'notnull' => true,
245
+                'length' => 64,
246
+                'default' => '',
247
+            ]);
248
+            $table->addColumn('uid', 'string', [
249
+                'notnull' => true,
250
+                'length' => 64,
251
+                'default' => '',
252
+            ]);
253
+            $table->setPrimaryKey(['gid', 'uid']);
254
+            $table->addIndex(['uid'], 'group_admin_uid');
255
+        }
256
+
257
+        if (!$schema->hasTable('groups')) {
258
+            $table = $schema->createTable('groups');
259
+            $table->addColumn('gid', 'string', [
260
+                'notnull' => true,
261
+                'length' => 64,
262
+                'default' => '',
263
+            ]);
264
+            $table->setPrimaryKey(['gid']);
265
+        }
266
+
267
+        if (!$schema->hasTable('preferences')) {
268
+            $table = $schema->createTable('preferences');
269
+            $table->addColumn('userid', 'string', [
270
+                'notnull' => true,
271
+                'length' => 64,
272
+                'default' => '',
273
+            ]);
274
+            $table->addColumn('appid', 'string', [
275
+                'notnull' => true,
276
+                'length' => 32,
277
+                'default' => '',
278
+            ]);
279
+            $table->addColumn('configkey', 'string', [
280
+                'notnull' => true,
281
+                'length' => 64,
282
+                'default' => '',
283
+            ]);
284
+            $table->addColumn('configvalue', 'text', [
285
+                'notnull' => false,
286
+            ]);
287
+            $table->setPrimaryKey(['userid', 'appid', 'configkey']);
288
+        }
289
+
290
+        if (!$schema->hasTable('properties')) {
291
+            $table = $schema->createTable('properties');
292
+            $table->addColumn('id', 'integer', [
293
+                'autoincrement' => true,
294
+                'notnull' => true,
295
+                'length' => 4,
296
+            ]);
297
+            $table->addColumn('userid', 'string', [
298
+                'notnull' => true,
299
+                'length' => 64,
300
+                'default' => '',
301
+            ]);
302
+            $table->addColumn('propertypath', 'string', [
303
+                'notnull' => true,
304
+                'length' => 255,
305
+                'default' => '',
306
+            ]);
307
+            $table->addColumn('propertyname', 'string', [
308
+                'notnull' => true,
309
+                'length' => 255,
310
+                'default' => '',
311
+            ]);
312
+            $table->addColumn('propertyvalue', 'text', [
313
+                'notnull' => true,
314
+            ]);
315
+            $table->setPrimaryKey(['id']);
316
+            $table->addIndex(['userid'], 'property_index');
317
+        }
318
+
319
+        if (!$schema->hasTable('share')) {
320
+            $table = $schema->createTable('share');
321
+            $table->addColumn('id', 'integer', [
322
+                'autoincrement' => true,
323
+                'notnull' => true,
324
+                'length' => 4,
325
+            ]);
326
+            $table->addColumn('share_type', 'smallint', [
327
+                'notnull' => true,
328
+                'length' => 1,
329
+                'default' => 0,
330
+            ]);
331
+            $table->addColumn('share_with', 'string', [
332
+                'notnull' => false,
333
+                'length' => 255,
334
+            ]);
335
+            $table->addColumn('password', 'string', [
336
+                'notnull' => false,
337
+                'length' => 255,
338
+            ]);
339
+            $table->addColumn('uid_owner', 'string', [
340
+                'notnull' => true,
341
+                'length' => 64,
342
+                'default' => '',
343
+            ]);
344
+            $table->addColumn('uid_initiator', 'string', [
345
+                'notnull' => false,
346
+                'length' => 64,
347
+            ]);
348
+            $table->addColumn('parent', 'integer', [
349
+                'notnull' => false,
350
+                'length' => 4,
351
+            ]);
352
+            $table->addColumn('item_type', 'string', [
353
+                'notnull' => true,
354
+                'length' => 64,
355
+                'default' => '',
356
+            ]);
357
+            $table->addColumn('item_source', 'string', [
358
+                'notnull' => false,
359
+                'length' => 255,
360
+            ]);
361
+            $table->addColumn('item_target', 'string', [
362
+                'notnull' => false,
363
+                'length' => 255,
364
+            ]);
365
+            $table->addColumn('file_source', 'integer', [
366
+                'notnull' => false,
367
+                'length' => 4,
368
+            ]);
369
+            $table->addColumn('file_target', 'string', [
370
+                'notnull' => false,
371
+                'length' => 512,
372
+            ]);
373
+            $table->addColumn('permissions', 'smallint', [
374
+                'notnull' => true,
375
+                'length' => 1,
376
+                'default' => 0,
377
+            ]);
378
+            $table->addColumn('stime', 'bigint', [
379
+                'notnull' => true,
380
+                'length' => 8,
381
+                'default' => 0,
382
+            ]);
383
+            $table->addColumn('accepted', 'smallint', [
384
+                'notnull' => true,
385
+                'length' => 1,
386
+                'default' => 0,
387
+            ]);
388
+            $table->addColumn('expiration', 'datetime', [
389
+                'notnull' => false,
390
+            ]);
391
+            $table->addColumn('token', 'string', [
392
+                'notnull' => false,
393
+                'length' => 32,
394
+            ]);
395
+            $table->addColumn('mail_send', 'smallint', [
396
+                'notnull' => true,
397
+                'length' => 1,
398
+                'default' => 0,
399
+            ]);
400
+            $table->addColumn('share_name', 'string', [
401
+                'notnull' => false,
402
+                'length' => 64,
403
+            ]);
404
+            $table->setPrimaryKey(['id']);
405
+            $table->addIndex(['item_type', 'share_type'], 'item_share_type_index');
406
+            $table->addIndex(['file_source'], 'file_source_index');
407
+            $table->addIndex(['token'], 'token_index');
408
+            $table->addIndex(['share_with'], 'share_with_index');
409
+            $table->addIndex(['parent'], 'parent_index');
410
+            $table->addIndex(['uid_owner'], 'owner_index');
411
+            $table->addIndex(['uid_initiator'], 'initiator_index');
412
+        }
413
+
414
+        if (!$schema->hasTable('jobs')) {
415
+            $table = $schema->createTable('jobs');
416
+            $table->addColumn('id', 'integer', [
417
+                'autoincrement' => true,
418
+                'notnull' => true,
419
+                'length' => 4,
420
+                'unsigned' => true,
421
+            ]);
422
+            $table->addColumn('class', 'string', [
423
+                'notnull' => true,
424
+                'length' => 255,
425
+                'default' => '',
426
+            ]);
427
+            $table->addColumn('argument', 'string', [
428
+                'notnull' => true,
429
+                'length' => 4000,
430
+                'default' => '',
431
+            ]);
432
+            $table->addColumn('last_run', 'integer', [
433
+                'notnull' => false,
434
+                'default' => 0,
435
+            ]);
436
+            $table->addColumn('last_checked', 'integer', [
437
+                'notnull' => false,
438
+                'default' => 0,
439
+            ]);
440
+            $table->addColumn('reserved_at', 'integer', [
441
+                'notnull' => false,
442
+                'default' => 0,
443
+            ]);
444
+            $table->addColumn('execution_duration', 'integer', [
445
+                'notnull' => true,
446
+                'default' => 0,
447
+            ]);
448
+            $table->setPrimaryKey(['id']);
449
+            $table->addIndex(['class'], 'job_class_index');
450
+        }
451
+
452
+        if (!$schema->hasTable('users')) {
453
+            $table = $schema->createTable('users');
454
+            $table->addColumn('uid', 'string', [
455
+                'notnull' => true,
456
+                'length' => 64,
457
+                'default' => '',
458
+            ]);
459
+            $table->addColumn('displayname', 'string', [
460
+                'notnull' => false,
461
+                'length' => 64,
462
+            ]);
463
+            $table->addColumn('password', 'string', [
464
+                'notnull' => true,
465
+                'length' => 255,
466
+                'default' => '',
467
+            ]);
468
+            $table->setPrimaryKey(['uid']);
469
+        }
470
+
471
+        if (!$schema->hasTable('authtoken')) {
472
+            $table = $schema->createTable('authtoken');
473
+            $table->addColumn('id', 'integer', [
474
+                'autoincrement' => true,
475
+                'notnull' => true,
476
+                'length' => 4,
477
+                'unsigned' => true,
478
+            ]);
479
+            $table->addColumn('uid', 'string', [
480
+                'notnull' => true,
481
+                'length' => 64,
482
+                'default' => '',
483
+            ]);
484
+            $table->addColumn('login_name', 'string', [
485
+                'notnull' => true,
486
+                'length' => 64,
487
+                'default' => '',
488
+            ]);
489
+            $table->addColumn('password', 'text', [
490
+                'notnull' => false,
491
+            ]);
492
+            $table->addColumn('name', 'text', [
493
+                'notnull' => true,
494
+                'default' => '',
495
+            ]);
496
+            $table->addColumn('token', 'string', [
497
+                'notnull' => true,
498
+                'length' => 200,
499
+                'default' => '',
500
+            ]);
501
+            $table->addColumn('type', 'smallint', [
502
+                'notnull' => true,
503
+                'length' => 2,
504
+                'default' => 0,
505
+                'unsigned' => true,
506
+            ]);
507
+            $table->addColumn('remember', 'smallint', [
508
+                'notnull' => true,
509
+                'length' => 1,
510
+                'default' => 0,
511
+                'unsigned' => true,
512
+            ]);
513
+            $table->addColumn('last_activity', 'integer', [
514
+                'notnull' => true,
515
+                'length' => 4,
516
+                'default' => 0,
517
+                'unsigned' => true,
518
+            ]);
519
+            $table->addColumn('last_check', 'integer', [
520
+                'notnull' => true,
521
+                'length' => 4,
522
+                'default' => 0,
523
+                'unsigned' => true,
524
+            ]);
525
+            $table->addColumn('scope', 'text', [
526
+                'notnull' => false,
527
+            ]);
528
+            $table->setPrimaryKey(['id']);
529
+            $table->addUniqueIndex(['token'], 'authtoken_token_index');
530
+            $table->addIndex(['last_activity'], 'authtoken_last_activity_idx');
531
+        }
532
+
533
+        if (!$schema->hasTable('bruteforce_attempts')) {
534
+            $table = $schema->createTable('bruteforce_attempts');
535
+            $table->addColumn('id', 'integer', [
536
+                'autoincrement' => true,
537
+                'notnull' => true,
538
+                'length' => 4,
539
+                'unsigned' => true,
540
+            ]);
541
+            $table->addColumn('action', 'string', [
542
+                'notnull' => true,
543
+                'length' => 64,
544
+                'default' => '',
545
+            ]);
546
+            $table->addColumn('occurred', 'integer', [
547
+                'notnull' => true,
548
+                'length' => 4,
549
+                'default' => 0,
550
+                'unsigned' => true,
551
+            ]);
552
+            $table->addColumn('ip', 'string', [
553
+                'notnull' => true,
554
+                'length' => 255,
555
+                'default' => '',
556
+            ]);
557
+            $table->addColumn('subnet', 'string', [
558
+                'notnull' => true,
559
+                'length' => 255,
560
+                'default' => '',
561
+            ]);
562
+            $table->addColumn('metadata', 'string', [
563
+                'notnull' => true,
564
+                'length' => 255,
565
+                'default' => '',
566
+            ]);
567
+            $table->setPrimaryKey(['id']);
568
+            $table->addIndex(['ip'], 'bruteforce_attempts_ip');
569
+            $table->addIndex(['subnet'], 'bruteforce_attempts_subnet');
570
+        }
571
+
572
+        if (!$schema->hasTable('vcategory')) {
573
+            $table = $schema->createTable('vcategory');
574
+            $table->addColumn('id', 'integer', [
575
+                'autoincrement' => true,
576
+                'notnull' => true,
577
+                'length' => 4,
578
+                'unsigned' => true,
579
+            ]);
580
+            $table->addColumn('uid', 'string', [
581
+                'notnull' => true,
582
+                'length' => 64,
583
+                'default' => '',
584
+            ]);
585
+            $table->addColumn('type', 'string', [
586
+                'notnull' => true,
587
+                'length' => 64,
588
+                'default' => '',
589
+            ]);
590
+            $table->addColumn('category', 'string', [
591
+                'notnull' => true,
592
+                'length' => 255,
593
+                'default' => '',
594
+            ]);
595
+            $table->setPrimaryKey(['id']);
596
+            $table->addIndex(['uid'], 'uid_index');
597
+            $table->addIndex(['type'], 'type_index');
598
+            $table->addIndex(['category'], 'category_index');
599
+        }
600
+
601
+        if (!$schema->hasTable('vcategory_to_object')) {
602
+            $table = $schema->createTable('vcategory_to_object');
603
+            $table->addColumn('objid', 'integer', [
604
+                'notnull' => true,
605
+                'length' => 4,
606
+                'default' => 0,
607
+                'unsigned' => true,
608
+            ]);
609
+            $table->addColumn('categoryid', 'integer', [
610
+                'notnull' => true,
611
+                'length' => 4,
612
+                'default' => 0,
613
+                'unsigned' => true,
614
+            ]);
615
+            $table->addColumn('type', 'string', [
616
+                'notnull' => true,
617
+                'length' => 64,
618
+                'default' => '',
619
+            ]);
620
+            $table->setPrimaryKey(['categoryid', 'objid', 'type']);
621
+            $table->addIndex(['objid', 'type'], 'vcategory_objectd_index');
622
+        }
623
+
624
+        if (!$schema->hasTable('systemtag')) {
625
+            $table = $schema->createTable('systemtag');
626
+            $table->addColumn('id', 'integer', [
627
+                'autoincrement' => true,
628
+                'notnull' => true,
629
+                'length' => 4,
630
+                'unsigned' => true,
631
+            ]);
632
+            $table->addColumn('name', 'string', [
633
+                'notnull' => true,
634
+                'length' => 64,
635
+                'default' => '',
636
+            ]);
637
+            $table->addColumn('visibility', 'smallint', [
638
+                'notnull' => true,
639
+                'length' => 1,
640
+                'default' => 1,
641
+            ]);
642
+            $table->addColumn('editable', 'smallint', [
643
+                'notnull' => true,
644
+                'length' => 1,
645
+                'default' => 1,
646
+            ]);
647
+            $table->setPrimaryKey(['id']);
648
+            $table->addUniqueIndex(['name', 'visibility', 'editable'], 'tag_ident');
649
+        }
650
+
651
+        if (!$schema->hasTable('systemtag_object_mapping')) {
652
+            $table = $schema->createTable('systemtag_object_mapping');
653
+            $table->addColumn('objectid', 'string', [
654
+                'notnull' => true,
655
+                'length' => 64,
656
+                'default' => '',
657
+            ]);
658
+            $table->addColumn('objecttype', 'string', [
659
+                'notnull' => true,
660
+                'length' => 64,
661
+                'default' => '',
662
+            ]);
663
+            $table->addColumn('systemtagid', 'integer', [
664
+                'notnull' => true,
665
+                'length' => 4,
666
+                'default' => 0,
667
+                'unsigned' => true,
668
+            ]);
669
+            $table->addUniqueIndex(['objecttype', 'objectid', 'systemtagid'], 'mapping');
670
+        }
671
+
672
+        if (!$schema->hasTable('systemtag_group')) {
673
+            $table = $schema->createTable('systemtag_group');
674
+            $table->addColumn('systemtagid', 'integer', [
675
+                'notnull' => true,
676
+                'length' => 4,
677
+                'default' => 0,
678
+                'unsigned' => true,
679
+            ]);
680
+            $table->addColumn('gid', 'string', [
681
+                'notnull' => true,
682
+            ]);
683
+            $table->setPrimaryKey(['gid', 'systemtagid']);
684
+        }
685
+
686
+        if (!$schema->hasTable('file_locks')) {
687
+            $table = $schema->createTable('file_locks');
688
+            $table->addColumn('id', 'integer', [
689
+                'autoincrement' => true,
690
+                'notnull' => true,
691
+                'length' => 4,
692
+                'unsigned' => true,
693
+            ]);
694
+            $table->addColumn('lock', 'integer', [
695
+                'notnull' => true,
696
+                'length' => 4,
697
+                'default' => 0,
698
+            ]);
699
+            $table->addColumn('key', 'string', [
700
+                'notnull' => true,
701
+                'length' => 64,
702
+            ]);
703
+            $table->addColumn('ttl', 'integer', [
704
+                'notnull' => true,
705
+                'length' => 4,
706
+                'default' => -1,
707
+            ]);
708
+            $table->setPrimaryKey(['id']);
709
+            $table->addUniqueIndex(['key'], 'lock_key_index');
710
+            $table->addIndex(['ttl'], 'lock_ttl_index');
711
+        }
712
+
713
+        if (!$schema->hasTable('comments')) {
714
+            $table = $schema->createTable('comments');
715
+            $table->addColumn('id', 'integer', [
716
+                'autoincrement' => true,
717
+                'notnull' => true,
718
+                'length' => 4,
719
+                'unsigned' => true,
720
+            ]);
721
+            $table->addColumn('parent_id', 'integer', [
722
+                'notnull' => true,
723
+                'length' => 4,
724
+                'default' => 0,
725
+                'unsigned' => true,
726
+            ]);
727
+            $table->addColumn('topmost_parent_id', 'integer', [
728
+                'notnull' => true,
729
+                'length' => 4,
730
+                'default' => 0,
731
+                'unsigned' => true,
732
+            ]);
733
+            $table->addColumn('children_count', 'integer', [
734
+                'notnull' => true,
735
+                'length' => 4,
736
+                'default' => 0,
737
+                'unsigned' => true,
738
+            ]);
739
+            $table->addColumn('actor_type', 'string', [
740
+                'notnull' => true,
741
+                'length' => 64,
742
+                'default' => '',
743
+            ]);
744
+            $table->addColumn('actor_id', 'string', [
745
+                'notnull' => true,
746
+                'length' => 64,
747
+                'default' => '',
748
+            ]);
749
+            $table->addColumn('message', 'text', [
750
+                'notnull' => false,
751
+            ]);
752
+            $table->addColumn('verb', 'string', [
753
+                'notnull' => false,
754
+                'length' => 64,
755
+            ]);
756
+            $table->addColumn('creation_timestamp', 'datetime', [
757
+                'notnull' => false,
758
+            ]);
759
+            $table->addColumn('latest_child_timestamp', 'datetime', [
760
+                'notnull' => false,
761
+            ]);
762
+            $table->addColumn('object_type', 'string', [
763
+                'notnull' => true,
764
+                'length' => 64,
765
+                'default' => '',
766
+            ]);
767
+            $table->addColumn('object_id', 'string', [
768
+                'notnull' => true,
769
+                'length' => 64,
770
+                'default' => '',
771
+            ]);
772
+            $table->addColumn('reference_id', 'string', [
773
+                'notnull' => false,
774
+                'length' => 64,
775
+            ]);
776
+            $table->setPrimaryKey(['id']);
777
+            $table->addIndex(['parent_id'], 'comments_parent_id_index');
778
+            $table->addIndex(['topmost_parent_id'], 'comments_topmost_parent_id_idx');
779
+            $table->addIndex(['object_type', 'object_id', 'creation_timestamp'], 'comments_object_index');
780
+            $table->addIndex(['actor_type', 'actor_id'], 'comments_actor_index');
781
+        }
782
+
783
+        if (!$schema->hasTable('comments_read_markers')) {
784
+            $table = $schema->createTable('comments_read_markers');
785
+            $table->addColumn('user_id', 'string', [
786
+                'notnull' => true,
787
+                'length' => 64,
788
+                'default' => '',
789
+            ]);
790
+            $table->addColumn('marker_datetime', 'datetime', [
791
+                'notnull' => false,
792
+            ]);
793
+            $table->addColumn('object_type', 'string', [
794
+                'notnull' => true,
795
+                'length' => 64,
796
+                'default' => '',
797
+            ]);
798
+            $table->addColumn('object_id', 'string', [
799
+                'notnull' => true,
800
+                'length' => 64,
801
+                'default' => '',
802
+            ]);
803
+            $table->addIndex(['object_type', 'object_id'], 'comments_marker_object_index');
804
+            $table->addUniqueIndex(['user_id', 'object_type', 'object_id'], 'comments_marker_index');
805
+        }
806
+
807
+        if (!$schema->hasTable('credentials')) {
808
+            $table = $schema->createTable('credentials');
809
+            $table->addColumn('user', 'string', [
810
+                'notnull' => true,
811
+                'length' => 64,
812
+            ]);
813
+            $table->addColumn('identifier', 'string', [
814
+                'notnull' => true,
815
+                'length' => 64,
816
+            ]);
817
+            $table->addColumn('credentials', 'text', [
818
+                'notnull' => false,
819
+            ]);
820
+            $table->setPrimaryKey(['user', 'identifier']);
821
+            $table->addIndex(['user'], 'credentials_user');
822
+        }
823
+
824
+        if (!$schema->hasTable('admin_sections')) {
825
+            $table = $schema->createTable('admin_sections');
826
+            $table->addColumn('id', 'string', [
827
+                'notnull' => true,
828
+                'length' => 64,
829
+            ]);
830
+            $table->addColumn('class', 'string', [
831
+                'notnull' => true,
832
+                'length' => 255,
833
+                'default' => '',
834
+            ]);
835
+            $table->addColumn('priority', 'smallint', [
836
+                'notnull' => true,
837
+                'length' => 1,
838
+                'default' => 0,
839
+            ]);
840
+            $table->setPrimaryKey(['id']);
841
+            $table->addUniqueIndex(['class'], 'admin_sections_class');
842
+        }
843
+
844
+        if (!$schema->hasTable('admin_settings')) {
845
+            $table = $schema->createTable('admin_settings');
846
+            $table->addColumn('id', 'integer', [
847
+                'autoincrement' => true,
848
+                'notnull' => true,
849
+                'length' => 4,
850
+            ]);
851
+            $table->addColumn('class', 'string', [
852
+                'notnull' => true,
853
+                'length' => 255,
854
+                'default' => '',
855
+            ]);
856
+            $table->addColumn('section', 'string', [
857
+                'notnull' => false,
858
+                'length' => 64,
859
+            ]);
860
+            $table->addColumn('priority', 'smallint', [
861
+                'notnull' => true,
862
+                'length' => 1,
863
+                'default' => 0,
864
+            ]);
865
+            $table->setPrimaryKey(['id']);
866
+            $table->addUniqueIndex(['class'], 'admin_settings_class');
867
+            $table->addIndex(['section'], 'admin_settings_section');
868
+        }
869
+
870
+        if (!$schema->hasTable('personal_sections')) {
871
+            $table = $schema->createTable('personal_sections');
872
+            $table->addColumn('id', 'string', [
873
+                'notnull' => true,
874
+                'length' => 64,
875
+            ]);
876
+            $table->addColumn('class', 'string', [
877
+                'notnull' => true,
878
+                'length' => 255,
879
+                'default' => '',
880
+            ]);
881
+            $table->addColumn('priority', 'smallint', [
882
+                'notnull' => true,
883
+                'length' => 1,
884
+                'default' => 0,
885
+            ]);
886
+            $table->setPrimaryKey(['id']);
887
+            $table->addUniqueIndex(['class'], 'personal_sections_class');
888
+        }
889
+
890
+        if (!$schema->hasTable('personal_settings')) {
891
+            $table = $schema->createTable('personal_settings');
892
+            $table->addColumn('id', 'integer', [
893
+                'autoincrement' => true,
894
+                'notnull' => true,
895
+                'length' => 4,
896
+            ]);
897
+            $table->addColumn('class', 'string', [
898
+                'notnull' => true,
899
+                'length' => 255,
900
+                'default' => '',
901
+            ]);
902
+            $table->addColumn('section', 'string', [
903
+                'notnull' => false,
904
+                'length' => 64,
905
+            ]);
906
+            $table->addColumn('priority', 'smallint', [
907
+                'notnull' => true,
908
+                'length' => 1,
909
+                'default' => 0,
910
+            ]);
911
+            $table->setPrimaryKey(['id']);
912
+            $table->addUniqueIndex(['class'], 'personal_settings_class');
913
+            $table->addIndex(['section'], 'personal_settings_section');
914
+        }
915
+
916
+        if (!$schema->hasTable('accounts')) {
917
+            $table = $schema->createTable('accounts');
918
+            $table->addColumn('uid', 'string', [
919
+                'notnull' => true,
920
+                'length' => 64,
921
+                'default' => '',
922
+            ]);
923
+            $table->addColumn('data', 'text', [
924
+                'notnull' => true,
925
+                'default' => '',
926
+            ]);
927
+            $table->setPrimaryKey(['uid']);
928
+        }
929
+        return $schema;
930
+    }
931 931
 
932 932
 }
Please login to merge, or discard this patch.
core/register_command.php 1 patch
Indentation   +117 added lines, -117 removed lines patch added patch discarded remove patch
@@ -49,132 +49,132 @@
 block discarded – undo
49 49
 $application->add(new OC\Core\Command\App\CheckCode());
50 50
 $application->add(new OC\Core\Command\L10n\CreateJs());
51 51
 $application->add(new \OC\Core\Command\Integrity\SignApp(
52
-		\OC::$server->getIntegrityCodeChecker(),
53
-		new \OC\IntegrityCheck\Helpers\FileAccessHelper(),
54
-		\OC::$server->getURLGenerator()
52
+        \OC::$server->getIntegrityCodeChecker(),
53
+        new \OC\IntegrityCheck\Helpers\FileAccessHelper(),
54
+        \OC::$server->getURLGenerator()
55 55
 ));
56 56
 $application->add(new \OC\Core\Command\Integrity\SignCore(
57
-		\OC::$server->getIntegrityCodeChecker(),
58
-		new \OC\IntegrityCheck\Helpers\FileAccessHelper()
57
+        \OC::$server->getIntegrityCodeChecker(),
58
+        new \OC\IntegrityCheck\Helpers\FileAccessHelper()
59 59
 ));
60 60
 $application->add(new \OC\Core\Command\Integrity\CheckApp(
61
-		\OC::$server->getIntegrityCodeChecker()
61
+        \OC::$server->getIntegrityCodeChecker()
62 62
 ));
63 63
 $application->add(new \OC\Core\Command\Integrity\CheckCore(
64
-		\OC::$server->getIntegrityCodeChecker()
64
+        \OC::$server->getIntegrityCodeChecker()
65 65
 ));
66 66
 
67 67
 
68 68
 if (\OC::$server->getConfig()->getSystemValue('installed', false)) {
69
-	$application->add(new OC\Core\Command\App\Disable(\OC::$server->getAppManager()));
70
-	$application->add(new OC\Core\Command\App\Enable(\OC::$server->getAppManager(), \OC::$server->getGroupManager()));
71
-	$application->add(new OC\Core\Command\App\Install());
72
-	$application->add(new OC\Core\Command\App\GetPath());
73
-	$application->add(new OC\Core\Command\App\ListApps(\OC::$server->getAppManager()));
74
-	$application->add(new OC\Core\Command\App\Remove(\OC::$server->getAppManager(), \OC::$server->query(\OC\Installer::class), \OC::$server->getLogger()));
75
-	$application->add(\OC::$server->query(\OC\Core\Command\App\Update::class));
76
-
77
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Cleanup::class));
78
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enforce::class));
79
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enable::class));
80
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Disable::class));
81
-	$application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\State::class));
82
-
83
-	$application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
84
-	$application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
85
-	$application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig()));
86
-
87
-	$application->add(\OC::$server->query(\OC\Core\Command\Broadcast\Test::class));
88
-
89
-	$application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig()));
90
-	$application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig()));
91
-	$application->add(new OC\Core\Command\Config\App\SetConfig(\OC::$server->getConfig()));
92
-	$application->add(new OC\Core\Command\Config\Import(\OC::$server->getConfig()));
93
-	$application->add(new OC\Core\Command\Config\ListConfigs(\OC::$server->getSystemConfig(), \OC::$server->getAppConfig()));
94
-	$application->add(new OC\Core\Command\Config\System\DeleteConfig(\OC::$server->getSystemConfig()));
95
-	$application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig()));
96
-	$application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
97
-
98
-	$application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
99
-	$application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger()));
100
-	$application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->getDatabaseConnection()));
101
-	$application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
102
-	$application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
103
-	$application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection()));
104
-	$application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->getDatabaseConnection()));
105
-	$application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getAppManager()));
106
-	$application->add(new OC\Core\Command\Db\Migrations\GenerateFromSchemaFileCommand(\OC::$server->getConfig(), \OC::$server->getAppManager(), \OC::$server->getDatabaseConnection()));
107
-	$application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getAppManager(), \OC::$server->getConfig()));
108
-
109
-	$application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
110
-	$application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
111
-	$application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
112
-	$application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
113
-	$application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
114
-	$application->add(new OC\Core\Command\Encryption\EncryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getAppManager(), \OC::$server->getConfig(), new \Symfony\Component\Console\Helper\QuestionHelper()));
115
-	$application->add(new OC\Core\Command\Encryption\DecryptAll(
116
-		\OC::$server->getEncryptionManager(),
117
-		\OC::$server->getAppManager(),
118
-		\OC::$server->getConfig(),
119
-		new \OC\Encryption\DecryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getUserManager(), new \OC\Files\View()),
120
-		new \Symfony\Component\Console\Helper\QuestionHelper())
121
-	);
122
-
123
-	$application->add(new OC\Core\Command\Log\Manage(\OC::$server->getConfig()));
124
-	$application->add(new OC\Core\Command\Log\File(\OC::$server->getConfig()));
125
-
126
-	$view = new \OC\Files\View();
127
-	$util = new \OC\Encryption\Util(
128
-		$view,
129
-		\OC::$server->getUserManager(),
130
-		\OC::$server->getGroupManager(),
131
-		\OC::$server->getConfig()
132
-	);
133
-	$application->add(new OC\Core\Command\Encryption\ChangeKeyStorageRoot(
134
-			$view,
135
-			\OC::$server->getUserManager(),
136
-			\OC::$server->getConfig(),
137
-			$util,
138
-			new \Symfony\Component\Console\Helper\QuestionHelper()
139
-		)
140
-	);
141
-	$application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util));
142
-
143
-	$application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory()));
144
-	$application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader()));
145
-	$application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector()));
146
-	$application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
147
-	$application->add(new OC\Core\Command\Maintenance\UpdateHtaccess());
148
-	$application->add(new OC\Core\Command\Maintenance\UpdateTheme(\OC::$server->getMimeTypeDetector(), \OC::$server->getMemCacheFactory()));
149
-
150
-	$application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->query(\OC\Installer::class)));
151
-	$application->add(new OC\Core\Command\Maintenance\Repair(
152
-		new \OC\Repair([], \OC::$server->getEventDispatcher()),
153
-		\OC::$server->getConfig(),
154
-		\OC::$server->getEventDispatcher(),
155
-		\OC::$server->getAppManager()
156
-	));
157
-
158
-	$application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
159
-	$application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
160
-	$application->add(new OC\Core\Command\User\Disable(\OC::$server->getUserManager()));
161
-	$application->add(new OC\Core\Command\User\Enable(\OC::$server->getUserManager()));
162
-	$application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
163
-	$application->add(new OC\Core\Command\User\Report(\OC::$server->getUserManager()));
164
-	$application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
165
-	$application->add(new OC\Core\Command\User\Setting(\OC::$server->getUserManager(), \OC::$server->getConfig(), \OC::$server->getDatabaseConnection()));
166
-	$application->add(new OC\Core\Command\User\ListCommand(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
167
-	$application->add(new OC\Core\Command\User\Info(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
168
-
169
-	$application->add(new OC\Core\Command\Group\Add(\OC::$server->getGroupManager()));
170
-	$application->add(new OC\Core\Command\Group\Delete(\OC::$server->getGroupManager()));
171
-	$application->add(new OC\Core\Command\Group\ListCommand(\OC::$server->getGroupManager()));
172
-	$application->add(new OC\Core\Command\Group\AddUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
173
-	$application->add(new OC\Core\Command\Group\RemoveUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
174
-
175
-	$application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(null), \OC::$server->getL10N('core')));
176
-	$application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager(null)));
177
-	$application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager(null)));
69
+    $application->add(new OC\Core\Command\App\Disable(\OC::$server->getAppManager()));
70
+    $application->add(new OC\Core\Command\App\Enable(\OC::$server->getAppManager(), \OC::$server->getGroupManager()));
71
+    $application->add(new OC\Core\Command\App\Install());
72
+    $application->add(new OC\Core\Command\App\GetPath());
73
+    $application->add(new OC\Core\Command\App\ListApps(\OC::$server->getAppManager()));
74
+    $application->add(new OC\Core\Command\App\Remove(\OC::$server->getAppManager(), \OC::$server->query(\OC\Installer::class), \OC::$server->getLogger()));
75
+    $application->add(\OC::$server->query(\OC\Core\Command\App\Update::class));
76
+
77
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Cleanup::class));
78
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enforce::class));
79
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Enable::class));
80
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\Disable::class));
81
+    $application->add(\OC::$server->query(\OC\Core\Command\TwoFactorAuth\State::class));
82
+
83
+    $application->add(new OC\Core\Command\Background\Cron(\OC::$server->getConfig()));
84
+    $application->add(new OC\Core\Command\Background\WebCron(\OC::$server->getConfig()));
85
+    $application->add(new OC\Core\Command\Background\Ajax(\OC::$server->getConfig()));
86
+
87
+    $application->add(\OC::$server->query(\OC\Core\Command\Broadcast\Test::class));
88
+
89
+    $application->add(new OC\Core\Command\Config\App\DeleteConfig(\OC::$server->getConfig()));
90
+    $application->add(new OC\Core\Command\Config\App\GetConfig(\OC::$server->getConfig()));
91
+    $application->add(new OC\Core\Command\Config\App\SetConfig(\OC::$server->getConfig()));
92
+    $application->add(new OC\Core\Command\Config\Import(\OC::$server->getConfig()));
93
+    $application->add(new OC\Core\Command\Config\ListConfigs(\OC::$server->getSystemConfig(), \OC::$server->getAppConfig()));
94
+    $application->add(new OC\Core\Command\Config\System\DeleteConfig(\OC::$server->getSystemConfig()));
95
+    $application->add(new OC\Core\Command\Config\System\GetConfig(\OC::$server->getSystemConfig()));
96
+    $application->add(new OC\Core\Command\Config\System\SetConfig(\OC::$server->getSystemConfig()));
97
+
98
+    $application->add(new OC\Core\Command\Db\ConvertType(\OC::$server->getConfig(), new \OC\DB\ConnectionFactory(\OC::$server->getSystemConfig())));
99
+    $application->add(new OC\Core\Command\Db\ConvertMysqlToMB4(\OC::$server->getConfig(), \OC::$server->getDatabaseConnection(), \OC::$server->getURLGenerator(), \OC::$server->getLogger()));
100
+    $application->add(new OC\Core\Command\Db\ConvertFilecacheBigInt(\OC::$server->getDatabaseConnection()));
101
+    $application->add(new OC\Core\Command\Db\AddMissingIndices(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
102
+    $application->add(new OC\Core\Command\Db\AddMissingColumns(\OC::$server->getDatabaseConnection(), \OC::$server->getEventDispatcher()));
103
+    $application->add(new OC\Core\Command\Db\Migrations\StatusCommand(\OC::$server->getDatabaseConnection()));
104
+    $application->add(new OC\Core\Command\Db\Migrations\MigrateCommand(\OC::$server->getDatabaseConnection()));
105
+    $application->add(new OC\Core\Command\Db\Migrations\GenerateCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getAppManager()));
106
+    $application->add(new OC\Core\Command\Db\Migrations\GenerateFromSchemaFileCommand(\OC::$server->getConfig(), \OC::$server->getAppManager(), \OC::$server->getDatabaseConnection()));
107
+    $application->add(new OC\Core\Command\Db\Migrations\ExecuteCommand(\OC::$server->getDatabaseConnection(), \OC::$server->getAppManager(), \OC::$server->getConfig()));
108
+
109
+    $application->add(new OC\Core\Command\Encryption\Disable(\OC::$server->getConfig()));
110
+    $application->add(new OC\Core\Command\Encryption\Enable(\OC::$server->getConfig(), \OC::$server->getEncryptionManager()));
111
+    $application->add(new OC\Core\Command\Encryption\ListModules(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
112
+    $application->add(new OC\Core\Command\Encryption\SetDefaultModule(\OC::$server->getEncryptionManager(), \OC::$server->getConfig()));
113
+    $application->add(new OC\Core\Command\Encryption\Status(\OC::$server->getEncryptionManager()));
114
+    $application->add(new OC\Core\Command\Encryption\EncryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getAppManager(), \OC::$server->getConfig(), new \Symfony\Component\Console\Helper\QuestionHelper()));
115
+    $application->add(new OC\Core\Command\Encryption\DecryptAll(
116
+        \OC::$server->getEncryptionManager(),
117
+        \OC::$server->getAppManager(),
118
+        \OC::$server->getConfig(),
119
+        new \OC\Encryption\DecryptAll(\OC::$server->getEncryptionManager(), \OC::$server->getUserManager(), new \OC\Files\View()),
120
+        new \Symfony\Component\Console\Helper\QuestionHelper())
121
+    );
122
+
123
+    $application->add(new OC\Core\Command\Log\Manage(\OC::$server->getConfig()));
124
+    $application->add(new OC\Core\Command\Log\File(\OC::$server->getConfig()));
125
+
126
+    $view = new \OC\Files\View();
127
+    $util = new \OC\Encryption\Util(
128
+        $view,
129
+        \OC::$server->getUserManager(),
130
+        \OC::$server->getGroupManager(),
131
+        \OC::$server->getConfig()
132
+    );
133
+    $application->add(new OC\Core\Command\Encryption\ChangeKeyStorageRoot(
134
+            $view,
135
+            \OC::$server->getUserManager(),
136
+            \OC::$server->getConfig(),
137
+            $util,
138
+            new \Symfony\Component\Console\Helper\QuestionHelper()
139
+        )
140
+    );
141
+    $application->add(new OC\Core\Command\Encryption\ShowKeyStorageRoot($util));
142
+
143
+    $application->add(new OC\Core\Command\Maintenance\DataFingerprint(\OC::$server->getConfig(), new \OC\AppFramework\Utility\TimeFactory()));
144
+    $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateDB(\OC::$server->getMimeTypeDetector(), \OC::$server->getMimeTypeLoader()));
145
+    $application->add(new OC\Core\Command\Maintenance\Mimetype\UpdateJS(\OC::$server->getMimeTypeDetector()));
146
+    $application->add(new OC\Core\Command\Maintenance\Mode(\OC::$server->getConfig()));
147
+    $application->add(new OC\Core\Command\Maintenance\UpdateHtaccess());
148
+    $application->add(new OC\Core\Command\Maintenance\UpdateTheme(\OC::$server->getMimeTypeDetector(), \OC::$server->getMemCacheFactory()));
149
+
150
+    $application->add(new OC\Core\Command\Upgrade(\OC::$server->getConfig(), \OC::$server->getLogger(), \OC::$server->query(\OC\Installer::class)));
151
+    $application->add(new OC\Core\Command\Maintenance\Repair(
152
+        new \OC\Repair([], \OC::$server->getEventDispatcher()),
153
+        \OC::$server->getConfig(),
154
+        \OC::$server->getEventDispatcher(),
155
+        \OC::$server->getAppManager()
156
+    ));
157
+
158
+    $application->add(new OC\Core\Command\User\Add(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
159
+    $application->add(new OC\Core\Command\User\Delete(\OC::$server->getUserManager()));
160
+    $application->add(new OC\Core\Command\User\Disable(\OC::$server->getUserManager()));
161
+    $application->add(new OC\Core\Command\User\Enable(\OC::$server->getUserManager()));
162
+    $application->add(new OC\Core\Command\User\LastSeen(\OC::$server->getUserManager()));
163
+    $application->add(new OC\Core\Command\User\Report(\OC::$server->getUserManager()));
164
+    $application->add(new OC\Core\Command\User\ResetPassword(\OC::$server->getUserManager()));
165
+    $application->add(new OC\Core\Command\User\Setting(\OC::$server->getUserManager(), \OC::$server->getConfig(), \OC::$server->getDatabaseConnection()));
166
+    $application->add(new OC\Core\Command\User\ListCommand(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
167
+    $application->add(new OC\Core\Command\User\Info(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
168
+
169
+    $application->add(new OC\Core\Command\Group\Add(\OC::$server->getGroupManager()));
170
+    $application->add(new OC\Core\Command\Group\Delete(\OC::$server->getGroupManager()));
171
+    $application->add(new OC\Core\Command\Group\ListCommand(\OC::$server->getGroupManager()));
172
+    $application->add(new OC\Core\Command\Group\AddUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
173
+    $application->add(new OC\Core\Command\Group\RemoveUser(\OC::$server->getUserManager(), \OC::$server->getGroupManager()));
174
+
175
+    $application->add(new OC\Core\Command\Security\ListCertificates(\OC::$server->getCertificateManager(null), \OC::$server->getL10N('core')));
176
+    $application->add(new OC\Core\Command\Security\ImportCertificate(\OC::$server->getCertificateManager(null)));
177
+    $application->add(new OC\Core\Command\Security\RemoveCertificate(\OC::$server->getCertificateManager(null)));
178 178
 } else {
179
-	$application->add(new OC\Core\Command\Maintenance\Install(\OC::$server->getSystemConfig()));
179
+    $application->add(new OC\Core\Command\Maintenance\Install(\OC::$server->getSystemConfig()));
180 180
 }
Please login to merge, or discard this patch.
core/Command/Db/AddMissingColumns.php 1 patch
Indentation   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -44,62 +44,62 @@
 block discarded – undo
44 44
  */
45 45
 class AddMissingColumns extends Command {
46 46
 
47
-	/** @var IDBConnection */
48
-	private $connection;
49
-
50
-	/** @var EventDispatcherInterface */
51
-	private $dispatcher;
52
-
53
-	public function __construct(IDBConnection $connection, EventDispatcherInterface $dispatcher) {
54
-		parent::__construct();
55
-
56
-		$this->connection = $connection;
57
-		$this->dispatcher = $dispatcher;
58
-	}
59
-
60
-	protected function configure() {
61
-		$this
62
-			->setName('db:add-missing-columns')
63
-			->setDescription('Add missing optional columns to the database tables');
64
-	}
65
-
66
-	protected function execute(InputInterface $input, OutputInterface $output) {
67
-		$this->addCoreColumns($output);
68
-
69
-		// Dispatch event so apps can also update columns if needed
70
-		$event = new GenericEvent($output);
71
-		$this->dispatcher->dispatch(IDBConnection::ADD_MISSING_COLUMNS_EVENT, $event);
72
-	}
73
-
74
-	/**
75
-	 * add missing indices to the share table
76
-	 *
77
-	 * @param OutputInterface $output
78
-	 * @throws \Doctrine\DBAL\Schema\SchemaException
79
-	 */
80
-	private function addCoreColumns(OutputInterface $output) {
81
-
82
-		$output->writeln('<info>Check columns of the comments table.</info>');
83
-
84
-		$schema = new SchemaWrapper($this->connection);
85
-		$updated = false;
86
-
87
-		if ($schema->hasTable('comments')) {
88
-			$table = $schema->getTable('comments');
89
-			if (!$table->hasColumn('reference_id')) {
90
-				$output->writeln('<info>Adding additional reference_id column to the comments table, this can take some time...</info>');
91
-				$table->addColumn('reference_id', 'string', [
92
-					'notnull' => false,
93
-					'length' => 64,
94
-				]);
95
-				$this->connection->migrateToSchema($schema->getWrappedSchema());
96
-				$updated = true;
97
-				$output->writeln('<info>Comments table updated successfully.</info>');
98
-			}
99
-		}
100
-
101
-		if (!$updated) {
102
-			$output->writeln('<info>Done.</info>');
103
-		}
104
-	}
47
+    /** @var IDBConnection */
48
+    private $connection;
49
+
50
+    /** @var EventDispatcherInterface */
51
+    private $dispatcher;
52
+
53
+    public function __construct(IDBConnection $connection, EventDispatcherInterface $dispatcher) {
54
+        parent::__construct();
55
+
56
+        $this->connection = $connection;
57
+        $this->dispatcher = $dispatcher;
58
+    }
59
+
60
+    protected function configure() {
61
+        $this
62
+            ->setName('db:add-missing-columns')
63
+            ->setDescription('Add missing optional columns to the database tables');
64
+    }
65
+
66
+    protected function execute(InputInterface $input, OutputInterface $output) {
67
+        $this->addCoreColumns($output);
68
+
69
+        // Dispatch event so apps can also update columns if needed
70
+        $event = new GenericEvent($output);
71
+        $this->dispatcher->dispatch(IDBConnection::ADD_MISSING_COLUMNS_EVENT, $event);
72
+    }
73
+
74
+    /**
75
+     * add missing indices to the share table
76
+     *
77
+     * @param OutputInterface $output
78
+     * @throws \Doctrine\DBAL\Schema\SchemaException
79
+     */
80
+    private function addCoreColumns(OutputInterface $output) {
81
+
82
+        $output->writeln('<info>Check columns of the comments table.</info>');
83
+
84
+        $schema = new SchemaWrapper($this->connection);
85
+        $updated = false;
86
+
87
+        if ($schema->hasTable('comments')) {
88
+            $table = $schema->getTable('comments');
89
+            if (!$table->hasColumn('reference_id')) {
90
+                $output->writeln('<info>Adding additional reference_id column to the comments table, this can take some time...</info>');
91
+                $table->addColumn('reference_id', 'string', [
92
+                    'notnull' => false,
93
+                    'length' => 64,
94
+                ]);
95
+                $this->connection->migrateToSchema($schema->getWrappedSchema());
96
+                $updated = true;
97
+                $output->writeln('<info>Comments table updated successfully.</info>');
98
+            }
99
+        }
100
+
101
+        if (!$updated) {
102
+            $output->writeln('<info>Done.</info>');
103
+        }
104
+    }
105 105
 }
Please login to merge, or discard this patch.