Passed
Push — master ( 645109...008e6d )
by Christoph
12:14 queued 12s
created
lib/private/User/User.php 2 patches
Indentation   +427 added lines, -427 removed lines patch added patch discarded remove patch
@@ -50,431 +50,431 @@
 block discarded – undo
50 50
 use Symfony\Component\EventDispatcher\GenericEvent;
51 51
 
52 52
 class User implements IUser {
53
-	/** @var string */
54
-	private $uid;
55
-
56
-	/** @var string */
57
-	private $displayName;
58
-
59
-	/** @var UserInterface|null */
60
-	private $backend;
61
-	/** @var EventDispatcherInterface */
62
-	private $dispatcher;
63
-
64
-	/** @var bool */
65
-	private $enabled;
66
-
67
-	/** @var Emitter|Manager */
68
-	private $emitter;
69
-
70
-	/** @var string */
71
-	private $home;
72
-
73
-	/** @var int */
74
-	private $lastLogin;
75
-
76
-	/** @var \OCP\IConfig */
77
-	private $config;
78
-
79
-	/** @var IAvatarManager */
80
-	private $avatarManager;
81
-
82
-	/** @var IURLGenerator */
83
-	private $urlGenerator;
84
-
85
-	public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
86
-		$this->uid = $uid;
87
-		$this->backend = $backend;
88
-		$this->dispatcher = $dispatcher;
89
-		$this->emitter = $emitter;
90
-		if(is_null($config)) {
91
-			$config = \OC::$server->getConfig();
92
-		}
93
-		$this->config = $config;
94
-		$this->urlGenerator = $urlGenerator;
95
-		$enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
96
-		$this->enabled = ($enabled === 'true');
97
-		$this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0);
98
-		if (is_null($this->urlGenerator)) {
99
-			$this->urlGenerator = \OC::$server->getURLGenerator();
100
-		}
101
-	}
102
-
103
-	/**
104
-	 * get the user id
105
-	 *
106
-	 * @return string
107
-	 */
108
-	public function getUID() {
109
-		return $this->uid;
110
-	}
111
-
112
-	/**
113
-	 * get the display name for the user, if no specific display name is set it will fallback to the user id
114
-	 *
115
-	 * @return string
116
-	 */
117
-	public function getDisplayName() {
118
-		if (!isset($this->displayName)) {
119
-			$displayName = '';
120
-			if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
121
-				// get display name and strip whitespace from the beginning and end of it
122
-				$backendDisplayName = $this->backend->getDisplayName($this->uid);
123
-				if (is_string($backendDisplayName)) {
124
-					$displayName = trim($backendDisplayName);
125
-				}
126
-			}
127
-
128
-			if (!empty($displayName)) {
129
-				$this->displayName = $displayName;
130
-			} else {
131
-				$this->displayName = $this->uid;
132
-			}
133
-		}
134
-		return $this->displayName;
135
-	}
136
-
137
-	/**
138
-	 * set the displayname for the user
139
-	 *
140
-	 * @param string $displayName
141
-	 * @return bool
142
-	 */
143
-	public function setDisplayName($displayName) {
144
-		$displayName = trim($displayName);
145
-		$oldDisplayName = $this->getDisplayName();
146
-		if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
147
-			$result = $this->backend->setDisplayName($this->uid, $displayName);
148
-			if ($result) {
149
-				$this->displayName = $displayName;
150
-				$this->triggerChange('displayName', $displayName, $oldDisplayName);
151
-			}
152
-			return $result !== false;
153
-		}
154
-		return false;
155
-	}
156
-
157
-	/**
158
-	 * set the email address of the user
159
-	 *
160
-	 * @param string|null $mailAddress
161
-	 * @return void
162
-	 * @since 9.0.0
163
-	 */
164
-	public function setEMailAddress($mailAddress) {
165
-		$oldMailAddress = $this->getEMailAddress();
166
-		if($oldMailAddress !== $mailAddress) {
167
-			if($mailAddress === '') {
168
-				$this->config->deleteUserValue($this->uid, 'settings', 'email');
169
-			} else {
170
-				$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
171
-			}
172
-			$this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
173
-		}
174
-	}
175
-
176
-	/**
177
-	 * returns the timestamp of the user's last login or 0 if the user did never
178
-	 * login
179
-	 *
180
-	 * @return int
181
-	 */
182
-	public function getLastLogin() {
183
-		return $this->lastLogin;
184
-	}
185
-
186
-	/**
187
-	 * updates the timestamp of the most recent login of this user
188
-	 */
189
-	public function updateLastLoginTimestamp() {
190
-		$firstTimeLogin = ($this->lastLogin === 0);
191
-		$this->lastLogin = time();
192
-		$this->config->setUserValue(
193
-			$this->uid, 'login', 'lastLogin', $this->lastLogin);
194
-
195
-		return $firstTimeLogin;
196
-	}
197
-
198
-	/**
199
-	 * Delete the user
200
-	 *
201
-	 * @return bool
202
-	 */
203
-	public function delete() {
204
-		$this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
205
-		if ($this->emitter) {
206
-			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
207
-		}
208
-		// get the home now because it won't return it after user deletion
209
-		$homePath = $this->getHome();
210
-		$result = $this->backend->deleteUser($this->uid);
211
-		if ($result) {
212
-
213
-			// FIXME: Feels like an hack - suggestions?
214
-
215
-			$groupManager = \OC::$server->getGroupManager();
216
-			// We have to delete the user from all groups
217
-			foreach ($groupManager->getUserGroupIds($this) as $groupId) {
218
-				$group = $groupManager->get($groupId);
219
-				if ($group) {
220
-					\OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
221
-					$group->removeUser($this);
222
-					\OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
223
-				}
224
-			}
225
-			// Delete the user's keys in preferences
226
-			\OC::$server->getConfig()->deleteAllUserValues($this->uid);
227
-
228
-			// Delete user files in /data/
229
-			if ($homePath !== false) {
230
-				// FIXME: this operates directly on FS, should use View instead...
231
-				// also this is not testable/mockable...
232
-				\OC_Helper::rmdirr($homePath);
233
-			}
234
-
235
-			// Delete the users entry in the storage table
236
-			Storage::remove('home::' . $this->uid);
237
-
238
-			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
239
-			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
240
-
241
-			$notification = \OC::$server->getNotificationManager()->createNotification();
242
-			$notification->setUser($this->uid);
243
-			\OC::$server->getNotificationManager()->markProcessed($notification);
244
-
245
-			/** @var AccountManager $accountManager */
246
-			$accountManager = \OC::$server->query(AccountManager::class);
247
-			$accountManager->deleteUser($this);
248
-
249
-			$this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
250
-			if ($this->emitter) {
251
-				$this->emitter->emit('\OC\User', 'postDelete', [$this]);
252
-			}
253
-		}
254
-		return !($result === false);
255
-	}
256
-
257
-	/**
258
-	 * Set the password of the user
259
-	 *
260
-	 * @param string $password
261
-	 * @param string $recoveryPassword for the encryption app to reset encryption keys
262
-	 * @return bool
263
-	 */
264
-	public function setPassword($password, $recoveryPassword = null) {
265
-		$this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
266
-			'password' => $password,
267
-			'recoveryPassword' => $recoveryPassword,
268
-		]));
269
-		if ($this->emitter) {
270
-			$this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
271
-		}
272
-		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
273
-			$result = $this->backend->setPassword($this->uid, $password);
274
-			$this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
275
-				'password' => $password,
276
-				'recoveryPassword' => $recoveryPassword,
277
-			]));
278
-			if ($this->emitter) {
279
-				$this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
280
-			}
281
-			return !($result === false);
282
-		} else {
283
-			return false;
284
-		}
285
-	}
286
-
287
-	/**
288
-	 * get the users home folder to mount
289
-	 *
290
-	 * @return string
291
-	 */
292
-	public function getHome() {
293
-		if (!$this->home) {
294
-			if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
295
-				$this->home = $home;
296
-			} elseif ($this->config) {
297
-				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
298
-			} else {
299
-				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
300
-			}
301
-		}
302
-		return $this->home;
303
-	}
304
-
305
-	/**
306
-	 * Get the name of the backend class the user is connected with
307
-	 *
308
-	 * @return string
309
-	 */
310
-	public function getBackendClassName() {
311
-		if($this->backend instanceof IUserBackend) {
312
-			return $this->backend->getBackendName();
313
-		}
314
-		return get_class($this->backend);
315
-	}
316
-
317
-	public function getBackend() {
318
-		return $this->backend;
319
-	}
320
-
321
-	/**
322
-	 * check if the backend allows the user to change his avatar on Personal page
323
-	 *
324
-	 * @return bool
325
-	 */
326
-	public function canChangeAvatar() {
327
-		if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
328
-			return $this->backend->canChangeAvatar($this->uid);
329
-		}
330
-		return true;
331
-	}
332
-
333
-	/**
334
-	 * check if the backend supports changing passwords
335
-	 *
336
-	 * @return bool
337
-	 */
338
-	public function canChangePassword() {
339
-		return $this->backend->implementsActions(Backend::SET_PASSWORD);
340
-	}
341
-
342
-	/**
343
-	 * check if the backend supports changing display names
344
-	 *
345
-	 * @return bool
346
-	 */
347
-	public function canChangeDisplayName() {
348
-		if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
349
-			return false;
350
-		}
351
-		return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
352
-	}
353
-
354
-	/**
355
-	 * check if the user is enabled
356
-	 *
357
-	 * @return bool
358
-	 */
359
-	public function isEnabled() {
360
-		return $this->enabled;
361
-	}
362
-
363
-	/**
364
-	 * set the enabled status for the user
365
-	 *
366
-	 * @param bool $enabled
367
-	 */
368
-	public function setEnabled(bool $enabled = true) {
369
-		$oldStatus = $this->isEnabled();
370
-		$this->enabled = $enabled;
371
-		if ($oldStatus !== $this->enabled) {
372
-			// TODO: First change the value, then trigger the event as done for all other properties.
373
-			$this->triggerChange('enabled', $enabled, $oldStatus);
374
-			$this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
375
-		}
376
-	}
377
-
378
-	/**
379
-	 * get the users email address
380
-	 *
381
-	 * @return string|null
382
-	 * @since 9.0.0
383
-	 */
384
-	public function getEMailAddress() {
385
-		return $this->config->getUserValue($this->uid, 'settings', 'email', null);
386
-	}
387
-
388
-	/**
389
-	 * get the users' quota
390
-	 *
391
-	 * @return string
392
-	 * @since 9.0.0
393
-	 */
394
-	public function getQuota() {
395
-		$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
396
-		if($quota === 'default') {
397
-			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
398
-		}
399
-		return $quota;
400
-	}
401
-
402
-	/**
403
-	 * set the users' quota
404
-	 *
405
-	 * @param string $quota
406
-	 * @return void
407
-	 * @since 9.0.0
408
-	 */
409
-	public function setQuota($quota) {
410
-		$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
411
-		if($quota !== 'none' and $quota !== 'default') {
412
-			$quota = OC_Helper::computerFileSize($quota);
413
-			$quota = OC_Helper::humanFileSize($quota);
414
-		}
415
-		if($quota !== $oldQuota) {
416
-			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
417
-			$this->triggerChange('quota', $quota, $oldQuota);
418
-		}
419
-	}
420
-
421
-	/**
422
-	 * get the avatar image if it exists
423
-	 *
424
-	 * @param int $size
425
-	 * @return IImage|null
426
-	 * @since 9.0.0
427
-	 */
428
-	public function getAvatarImage($size) {
429
-		// delay the initialization
430
-		if (is_null($this->avatarManager)) {
431
-			$this->avatarManager = \OC::$server->getAvatarManager();
432
-		}
433
-
434
-		$avatar = $this->avatarManager->getAvatar($this->uid);
435
-		$image = $avatar->get(-1);
436
-		if ($image) {
437
-			return $image;
438
-		}
439
-
440
-		return null;
441
-	}
442
-
443
-	/**
444
-	 * get the federation cloud id
445
-	 *
446
-	 * @return string
447
-	 * @since 9.0.0
448
-	 */
449
-	public function getCloudId() {
450
-		$uid = $this->getUID();
451
-		$server = $this->urlGenerator->getAbsoluteURL('/');
452
-		$server =  rtrim($this->removeProtocolFromUrl($server), '/');
453
-		return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
454
-	}
455
-
456
-	/**
457
-	 * @param string $url
458
-	 * @return string
459
-	 */
460
-	private function removeProtocolFromUrl($url) {
461
-		if (strpos($url, 'https://') === 0) {
462
-			return substr($url, strlen('https://'));
463
-		} else if (strpos($url, 'http://') === 0) {
464
-			return substr($url, strlen('http://'));
465
-		}
466
-
467
-		return $url;
468
-	}
469
-
470
-	public function triggerChange($feature, $value = null, $oldValue = null) {
471
-		$this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
472
-			'feature' => $feature,
473
-			'value' => $value,
474
-			'oldValue' => $oldValue,
475
-		]));
476
-		if ($this->emitter) {
477
-			$this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
478
-		}
479
-	}
53
+    /** @var string */
54
+    private $uid;
55
+
56
+    /** @var string */
57
+    private $displayName;
58
+
59
+    /** @var UserInterface|null */
60
+    private $backend;
61
+    /** @var EventDispatcherInterface */
62
+    private $dispatcher;
63
+
64
+    /** @var bool */
65
+    private $enabled;
66
+
67
+    /** @var Emitter|Manager */
68
+    private $emitter;
69
+
70
+    /** @var string */
71
+    private $home;
72
+
73
+    /** @var int */
74
+    private $lastLogin;
75
+
76
+    /** @var \OCP\IConfig */
77
+    private $config;
78
+
79
+    /** @var IAvatarManager */
80
+    private $avatarManager;
81
+
82
+    /** @var IURLGenerator */
83
+    private $urlGenerator;
84
+
85
+    public function __construct(string $uid, ?UserInterface $backend, EventDispatcherInterface $dispatcher, $emitter = null, IConfig $config = null, $urlGenerator = null) {
86
+        $this->uid = $uid;
87
+        $this->backend = $backend;
88
+        $this->dispatcher = $dispatcher;
89
+        $this->emitter = $emitter;
90
+        if(is_null($config)) {
91
+            $config = \OC::$server->getConfig();
92
+        }
93
+        $this->config = $config;
94
+        $this->urlGenerator = $urlGenerator;
95
+        $enabled = $this->config->getUserValue($uid, 'core', 'enabled', 'true');
96
+        $this->enabled = ($enabled === 'true');
97
+        $this->lastLogin = $this->config->getUserValue($uid, 'login', 'lastLogin', 0);
98
+        if (is_null($this->urlGenerator)) {
99
+            $this->urlGenerator = \OC::$server->getURLGenerator();
100
+        }
101
+    }
102
+
103
+    /**
104
+     * get the user id
105
+     *
106
+     * @return string
107
+     */
108
+    public function getUID() {
109
+        return $this->uid;
110
+    }
111
+
112
+    /**
113
+     * get the display name for the user, if no specific display name is set it will fallback to the user id
114
+     *
115
+     * @return string
116
+     */
117
+    public function getDisplayName() {
118
+        if (!isset($this->displayName)) {
119
+            $displayName = '';
120
+            if ($this->backend && $this->backend->implementsActions(Backend::GET_DISPLAYNAME)) {
121
+                // get display name and strip whitespace from the beginning and end of it
122
+                $backendDisplayName = $this->backend->getDisplayName($this->uid);
123
+                if (is_string($backendDisplayName)) {
124
+                    $displayName = trim($backendDisplayName);
125
+                }
126
+            }
127
+
128
+            if (!empty($displayName)) {
129
+                $this->displayName = $displayName;
130
+            } else {
131
+                $this->displayName = $this->uid;
132
+            }
133
+        }
134
+        return $this->displayName;
135
+    }
136
+
137
+    /**
138
+     * set the displayname for the user
139
+     *
140
+     * @param string $displayName
141
+     * @return bool
142
+     */
143
+    public function setDisplayName($displayName) {
144
+        $displayName = trim($displayName);
145
+        $oldDisplayName = $this->getDisplayName();
146
+        if ($this->backend->implementsActions(Backend::SET_DISPLAYNAME) && !empty($displayName) && $displayName !== $oldDisplayName) {
147
+            $result = $this->backend->setDisplayName($this->uid, $displayName);
148
+            if ($result) {
149
+                $this->displayName = $displayName;
150
+                $this->triggerChange('displayName', $displayName, $oldDisplayName);
151
+            }
152
+            return $result !== false;
153
+        }
154
+        return false;
155
+    }
156
+
157
+    /**
158
+     * set the email address of the user
159
+     *
160
+     * @param string|null $mailAddress
161
+     * @return void
162
+     * @since 9.0.0
163
+     */
164
+    public function setEMailAddress($mailAddress) {
165
+        $oldMailAddress = $this->getEMailAddress();
166
+        if($oldMailAddress !== $mailAddress) {
167
+            if($mailAddress === '') {
168
+                $this->config->deleteUserValue($this->uid, 'settings', 'email');
169
+            } else {
170
+                $this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
171
+            }
172
+            $this->triggerChange('eMailAddress', $mailAddress, $oldMailAddress);
173
+        }
174
+    }
175
+
176
+    /**
177
+     * returns the timestamp of the user's last login or 0 if the user did never
178
+     * login
179
+     *
180
+     * @return int
181
+     */
182
+    public function getLastLogin() {
183
+        return $this->lastLogin;
184
+    }
185
+
186
+    /**
187
+     * updates the timestamp of the most recent login of this user
188
+     */
189
+    public function updateLastLoginTimestamp() {
190
+        $firstTimeLogin = ($this->lastLogin === 0);
191
+        $this->lastLogin = time();
192
+        $this->config->setUserValue(
193
+            $this->uid, 'login', 'lastLogin', $this->lastLogin);
194
+
195
+        return $firstTimeLogin;
196
+    }
197
+
198
+    /**
199
+     * Delete the user
200
+     *
201
+     * @return bool
202
+     */
203
+    public function delete() {
204
+        $this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
205
+        if ($this->emitter) {
206
+            $this->emitter->emit('\OC\User', 'preDelete', [$this]);
207
+        }
208
+        // get the home now because it won't return it after user deletion
209
+        $homePath = $this->getHome();
210
+        $result = $this->backend->deleteUser($this->uid);
211
+        if ($result) {
212
+
213
+            // FIXME: Feels like an hack - suggestions?
214
+
215
+            $groupManager = \OC::$server->getGroupManager();
216
+            // We have to delete the user from all groups
217
+            foreach ($groupManager->getUserGroupIds($this) as $groupId) {
218
+                $group = $groupManager->get($groupId);
219
+                if ($group) {
220
+                    \OC_Hook::emit("OC_Group", "pre_removeFromGroup", ["run" => true, "uid" => $this->uid, "gid" => $groupId]);
221
+                    $group->removeUser($this);
222
+                    \OC_Hook::emit("OC_User", "post_removeFromGroup", ["uid" => $this->uid, "gid" => $groupId]);
223
+                }
224
+            }
225
+            // Delete the user's keys in preferences
226
+            \OC::$server->getConfig()->deleteAllUserValues($this->uid);
227
+
228
+            // Delete user files in /data/
229
+            if ($homePath !== false) {
230
+                // FIXME: this operates directly on FS, should use View instead...
231
+                // also this is not testable/mockable...
232
+                \OC_Helper::rmdirr($homePath);
233
+            }
234
+
235
+            // Delete the users entry in the storage table
236
+            Storage::remove('home::' . $this->uid);
237
+
238
+            \OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
239
+            \OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
240
+
241
+            $notification = \OC::$server->getNotificationManager()->createNotification();
242
+            $notification->setUser($this->uid);
243
+            \OC::$server->getNotificationManager()->markProcessed($notification);
244
+
245
+            /** @var AccountManager $accountManager */
246
+            $accountManager = \OC::$server->query(AccountManager::class);
247
+            $accountManager->deleteUser($this);
248
+
249
+            $this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
250
+            if ($this->emitter) {
251
+                $this->emitter->emit('\OC\User', 'postDelete', [$this]);
252
+            }
253
+        }
254
+        return !($result === false);
255
+    }
256
+
257
+    /**
258
+     * Set the password of the user
259
+     *
260
+     * @param string $password
261
+     * @param string $recoveryPassword for the encryption app to reset encryption keys
262
+     * @return bool
263
+     */
264
+    public function setPassword($password, $recoveryPassword = null) {
265
+        $this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
266
+            'password' => $password,
267
+            'recoveryPassword' => $recoveryPassword,
268
+        ]));
269
+        if ($this->emitter) {
270
+            $this->emitter->emit('\OC\User', 'preSetPassword', [$this, $password, $recoveryPassword]);
271
+        }
272
+        if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
273
+            $result = $this->backend->setPassword($this->uid, $password);
274
+            $this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
275
+                'password' => $password,
276
+                'recoveryPassword' => $recoveryPassword,
277
+            ]));
278
+            if ($this->emitter) {
279
+                $this->emitter->emit('\OC\User', 'postSetPassword', [$this, $password, $recoveryPassword]);
280
+            }
281
+            return !($result === false);
282
+        } else {
283
+            return false;
284
+        }
285
+    }
286
+
287
+    /**
288
+     * get the users home folder to mount
289
+     *
290
+     * @return string
291
+     */
292
+    public function getHome() {
293
+        if (!$this->home) {
294
+            if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
295
+                $this->home = $home;
296
+            } elseif ($this->config) {
297
+                $this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
298
+            } else {
299
+                $this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
300
+            }
301
+        }
302
+        return $this->home;
303
+    }
304
+
305
+    /**
306
+     * Get the name of the backend class the user is connected with
307
+     *
308
+     * @return string
309
+     */
310
+    public function getBackendClassName() {
311
+        if($this->backend instanceof IUserBackend) {
312
+            return $this->backend->getBackendName();
313
+        }
314
+        return get_class($this->backend);
315
+    }
316
+
317
+    public function getBackend() {
318
+        return $this->backend;
319
+    }
320
+
321
+    /**
322
+     * check if the backend allows the user to change his avatar on Personal page
323
+     *
324
+     * @return bool
325
+     */
326
+    public function canChangeAvatar() {
327
+        if ($this->backend->implementsActions(Backend::PROVIDE_AVATAR)) {
328
+            return $this->backend->canChangeAvatar($this->uid);
329
+        }
330
+        return true;
331
+    }
332
+
333
+    /**
334
+     * check if the backend supports changing passwords
335
+     *
336
+     * @return bool
337
+     */
338
+    public function canChangePassword() {
339
+        return $this->backend->implementsActions(Backend::SET_PASSWORD);
340
+    }
341
+
342
+    /**
343
+     * check if the backend supports changing display names
344
+     *
345
+     * @return bool
346
+     */
347
+    public function canChangeDisplayName() {
348
+        if ($this->config->getSystemValue('allow_user_to_change_display_name') === false) {
349
+            return false;
350
+        }
351
+        return $this->backend->implementsActions(Backend::SET_DISPLAYNAME);
352
+    }
353
+
354
+    /**
355
+     * check if the user is enabled
356
+     *
357
+     * @return bool
358
+     */
359
+    public function isEnabled() {
360
+        return $this->enabled;
361
+    }
362
+
363
+    /**
364
+     * set the enabled status for the user
365
+     *
366
+     * @param bool $enabled
367
+     */
368
+    public function setEnabled(bool $enabled = true) {
369
+        $oldStatus = $this->isEnabled();
370
+        $this->enabled = $enabled;
371
+        if ($oldStatus !== $this->enabled) {
372
+            // TODO: First change the value, then trigger the event as done for all other properties.
373
+            $this->triggerChange('enabled', $enabled, $oldStatus);
374
+            $this->config->setUserValue($this->uid, 'core', 'enabled', $enabled ? 'true' : 'false');
375
+        }
376
+    }
377
+
378
+    /**
379
+     * get the users email address
380
+     *
381
+     * @return string|null
382
+     * @since 9.0.0
383
+     */
384
+    public function getEMailAddress() {
385
+        return $this->config->getUserValue($this->uid, 'settings', 'email', null);
386
+    }
387
+
388
+    /**
389
+     * get the users' quota
390
+     *
391
+     * @return string
392
+     * @since 9.0.0
393
+     */
394
+    public function getQuota() {
395
+        $quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
396
+        if($quota === 'default') {
397
+            $quota = $this->config->getAppValue('files', 'default_quota', 'none');
398
+        }
399
+        return $quota;
400
+    }
401
+
402
+    /**
403
+     * set the users' quota
404
+     *
405
+     * @param string $quota
406
+     * @return void
407
+     * @since 9.0.0
408
+     */
409
+    public function setQuota($quota) {
410
+        $oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
411
+        if($quota !== 'none' and $quota !== 'default') {
412
+            $quota = OC_Helper::computerFileSize($quota);
413
+            $quota = OC_Helper::humanFileSize($quota);
414
+        }
415
+        if($quota !== $oldQuota) {
416
+            $this->config->setUserValue($this->uid, 'files', 'quota', $quota);
417
+            $this->triggerChange('quota', $quota, $oldQuota);
418
+        }
419
+    }
420
+
421
+    /**
422
+     * get the avatar image if it exists
423
+     *
424
+     * @param int $size
425
+     * @return IImage|null
426
+     * @since 9.0.0
427
+     */
428
+    public function getAvatarImage($size) {
429
+        // delay the initialization
430
+        if (is_null($this->avatarManager)) {
431
+            $this->avatarManager = \OC::$server->getAvatarManager();
432
+        }
433
+
434
+        $avatar = $this->avatarManager->getAvatar($this->uid);
435
+        $image = $avatar->get(-1);
436
+        if ($image) {
437
+            return $image;
438
+        }
439
+
440
+        return null;
441
+    }
442
+
443
+    /**
444
+     * get the federation cloud id
445
+     *
446
+     * @return string
447
+     * @since 9.0.0
448
+     */
449
+    public function getCloudId() {
450
+        $uid = $this->getUID();
451
+        $server = $this->urlGenerator->getAbsoluteURL('/');
452
+        $server =  rtrim($this->removeProtocolFromUrl($server), '/');
453
+        return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
454
+    }
455
+
456
+    /**
457
+     * @param string $url
458
+     * @return string
459
+     */
460
+    private function removeProtocolFromUrl($url) {
461
+        if (strpos($url, 'https://') === 0) {
462
+            return substr($url, strlen('https://'));
463
+        } else if (strpos($url, 'http://') === 0) {
464
+            return substr($url, strlen('http://'));
465
+        }
466
+
467
+        return $url;
468
+    }
469
+
470
+    public function triggerChange($feature, $value = null, $oldValue = null) {
471
+        $this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
472
+            'feature' => $feature,
473
+            'value' => $value,
474
+            'oldValue' => $oldValue,
475
+        ]));
476
+        if ($this->emitter) {
477
+            $this->emitter->emit('\OC\User', 'changeUser', [$this, $feature, $value, $oldValue]);
478
+        }
479
+    }
480 480
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -87,7 +87,7 @@  discard block
 block discarded – undo
87 87
 		$this->backend = $backend;
88 88
 		$this->dispatcher = $dispatcher;
89 89
 		$this->emitter = $emitter;
90
-		if(is_null($config)) {
90
+		if (is_null($config)) {
91 91
 			$config = \OC::$server->getConfig();
92 92
 		}
93 93
 		$this->config = $config;
@@ -163,8 +163,8 @@  discard block
 block discarded – undo
163 163
 	 */
164 164
 	public function setEMailAddress($mailAddress) {
165 165
 		$oldMailAddress = $this->getEMailAddress();
166
-		if($oldMailAddress !== $mailAddress) {
167
-			if($mailAddress === '') {
166
+		if ($oldMailAddress !== $mailAddress) {
167
+			if ($mailAddress === '') {
168 168
 				$this->config->deleteUserValue($this->uid, 'settings', 'email');
169 169
 			} else {
170 170
 				$this->config->setUserValue($this->uid, 'settings', 'email', $mailAddress);
@@ -201,7 +201,7 @@  discard block
 block discarded – undo
201 201
 	 * @return bool
202 202
 	 */
203 203
 	public function delete() {
204
-		$this->dispatcher->dispatch(IUser::class . '::preDelete', new GenericEvent($this));
204
+		$this->dispatcher->dispatch(IUser::class.'::preDelete', new GenericEvent($this));
205 205
 		if ($this->emitter) {
206 206
 			$this->emitter->emit('\OC\User', 'preDelete', [$this]);
207 207
 		}
@@ -233,7 +233,7 @@  discard block
 block discarded – undo
233 233
 			}
234 234
 
235 235
 			// Delete the users entry in the storage table
236
-			Storage::remove('home::' . $this->uid);
236
+			Storage::remove('home::'.$this->uid);
237 237
 
238 238
 			\OC::$server->getCommentsManager()->deleteReferencesOfActor('users', $this->uid);
239 239
 			\OC::$server->getCommentsManager()->deleteReadMarksFromUser($this);
@@ -246,7 +246,7 @@  discard block
 block discarded – undo
246 246
 			$accountManager = \OC::$server->query(AccountManager::class);
247 247
 			$accountManager->deleteUser($this);
248 248
 
249
-			$this->dispatcher->dispatch(IUser::class . '::postDelete', new GenericEvent($this));
249
+			$this->dispatcher->dispatch(IUser::class.'::postDelete', new GenericEvent($this));
250 250
 			if ($this->emitter) {
251 251
 				$this->emitter->emit('\OC\User', 'postDelete', [$this]);
252 252
 			}
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 	 * @return bool
263 263
 	 */
264 264
 	public function setPassword($password, $recoveryPassword = null) {
265
-		$this->dispatcher->dispatch(IUser::class . '::preSetPassword', new GenericEvent($this, [
265
+		$this->dispatcher->dispatch(IUser::class.'::preSetPassword', new GenericEvent($this, [
266 266
 			'password' => $password,
267 267
 			'recoveryPassword' => $recoveryPassword,
268 268
 		]));
@@ -271,7 +271,7 @@  discard block
 block discarded – undo
271 271
 		}
272 272
 		if ($this->backend->implementsActions(Backend::SET_PASSWORD)) {
273 273
 			$result = $this->backend->setPassword($this->uid, $password);
274
-			$this->dispatcher->dispatch(IUser::class . '::postSetPassword', new GenericEvent($this, [
274
+			$this->dispatcher->dispatch(IUser::class.'::postSetPassword', new GenericEvent($this, [
275 275
 				'password' => $password,
276 276
 				'recoveryPassword' => $recoveryPassword,
277 277
 			]));
@@ -294,9 +294,9 @@  discard block
 block discarded – undo
294 294
 			if ($this->backend->implementsActions(Backend::GET_HOME) and $home = $this->backend->getHome($this->uid)) {
295 295
 				$this->home = $home;
296 296
 			} elseif ($this->config) {
297
-				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT . '/data') . '/' . $this->uid;
297
+				$this->home = $this->config->getSystemValue('datadirectory', \OC::$SERVERROOT.'/data').'/'.$this->uid;
298 298
 			} else {
299
-				$this->home = \OC::$SERVERROOT . '/data/' . $this->uid;
299
+				$this->home = \OC::$SERVERROOT.'/data/'.$this->uid;
300 300
 			}
301 301
 		}
302 302
 		return $this->home;
@@ -308,7 +308,7 @@  discard block
 block discarded – undo
308 308
 	 * @return string
309 309
 	 */
310 310
 	public function getBackendClassName() {
311
-		if($this->backend instanceof IUserBackend) {
311
+		if ($this->backend instanceof IUserBackend) {
312 312
 			return $this->backend->getBackendName();
313 313
 		}
314 314
 		return get_class($this->backend);
@@ -393,7 +393,7 @@  discard block
 block discarded – undo
393 393
 	 */
394 394
 	public function getQuota() {
395 395
 		$quota = $this->config->getUserValue($this->uid, 'files', 'quota', 'default');
396
-		if($quota === 'default') {
396
+		if ($quota === 'default') {
397 397
 			$quota = $this->config->getAppValue('files', 'default_quota', 'none');
398 398
 		}
399 399
 		return $quota;
@@ -408,11 +408,11 @@  discard block
 block discarded – undo
408 408
 	 */
409 409
 	public function setQuota($quota) {
410 410
 		$oldQuota = $this->config->getUserValue($this->uid, 'files', 'quota', '');
411
-		if($quota !== 'none' and $quota !== 'default') {
411
+		if ($quota !== 'none' and $quota !== 'default') {
412 412
 			$quota = OC_Helper::computerFileSize($quota);
413 413
 			$quota = OC_Helper::humanFileSize($quota);
414 414
 		}
415
-		if($quota !== $oldQuota) {
415
+		if ($quota !== $oldQuota) {
416 416
 			$this->config->setUserValue($this->uid, 'files', 'quota', $quota);
417 417
 			$this->triggerChange('quota', $quota, $oldQuota);
418 418
 		}
@@ -449,7 +449,7 @@  discard block
 block discarded – undo
449 449
 	public function getCloudId() {
450 450
 		$uid = $this->getUID();
451 451
 		$server = $this->urlGenerator->getAbsoluteURL('/');
452
-		$server =  rtrim($this->removeProtocolFromUrl($server), '/');
452
+		$server = rtrim($this->removeProtocolFromUrl($server), '/');
453 453
 		return \OC::$server->getCloudIdManager()->getCloudId($uid, $server)->getId();
454 454
 	}
455 455
 
@@ -468,7 +468,7 @@  discard block
 block discarded – undo
468 468
 	}
469 469
 
470 470
 	public function triggerChange($feature, $value = null, $oldValue = null) {
471
-		$this->dispatcher->dispatch(IUser::class . '::changeUser', new GenericEvent($this, [
471
+		$this->dispatcher->dispatch(IUser::class.'::changeUser', new GenericEvent($this, [
472 472
 			'feature' => $feature,
473 473
 			'value' => $value,
474 474
 			'oldValue' => $oldValue,
Please login to merge, or discard this patch.
lib/private/DateTimeZone.php 1 patch
Indentation   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -30,100 +30,100 @@
 block discarded – undo
30 30
 use OCP\ISession;
31 31
 
32 32
 class DateTimeZone implements IDateTimeZone {
33
-	/** @var IConfig */
34
-	protected $config;
33
+    /** @var IConfig */
34
+    protected $config;
35 35
 
36
-	/** @var ISession */
37
-	protected $session;
36
+    /** @var ISession */
37
+    protected $session;
38 38
 
39
-	/**
40
-	 * Constructor
41
-	 *
42
-	 * @param IConfig $config
43
-	 * @param ISession $session
44
-	 */
45
-	public function __construct(IConfig $config, ISession $session) {
46
-		$this->config = $config;
47
-		$this->session = $session;
48
-	}
39
+    /**
40
+     * Constructor
41
+     *
42
+     * @param IConfig $config
43
+     * @param ISession $session
44
+     */
45
+    public function __construct(IConfig $config, ISession $session) {
46
+        $this->config = $config;
47
+        $this->session = $session;
48
+    }
49 49
 
50
-	/**
51
-	 * Get the timezone of the current user, based on his session information and config data
52
-	 *
53
-	 * @param bool|int $timestamp
54
-	 * @return \DateTimeZone
55
-	 */
56
-	public function getTimeZone($timestamp = false) {
57
-		$timeZone = $this->config->getUserValue($this->session->get('user_id'), 'core', 'timezone', null);
58
-		if ($timeZone === null) {
59
-			if ($this->session->exists('timezone')) {
60
-				return $this->guessTimeZoneFromOffset($this->session->get('timezone'), $timestamp);
61
-			}
62
-			$timeZone = $this->getDefaultTimeZone();
63
-		}
50
+    /**
51
+     * Get the timezone of the current user, based on his session information and config data
52
+     *
53
+     * @param bool|int $timestamp
54
+     * @return \DateTimeZone
55
+     */
56
+    public function getTimeZone($timestamp = false) {
57
+        $timeZone = $this->config->getUserValue($this->session->get('user_id'), 'core', 'timezone', null);
58
+        if ($timeZone === null) {
59
+            if ($this->session->exists('timezone')) {
60
+                return $this->guessTimeZoneFromOffset($this->session->get('timezone'), $timestamp);
61
+            }
62
+            $timeZone = $this->getDefaultTimeZone();
63
+        }
64 64
 
65
-		try {
66
-			return new \DateTimeZone($timeZone);
67
-		} catch (\Exception $e) {
68
-			\OCP\Util::writeLog('datetimezone', 'Failed to created DateTimeZone "' . $timeZone . "'", ILogger::DEBUG);
69
-			return new \DateTimeZone($this->getDefaultTimeZone());
70
-		}
71
-	}
65
+        try {
66
+            return new \DateTimeZone($timeZone);
67
+        } catch (\Exception $e) {
68
+            \OCP\Util::writeLog('datetimezone', 'Failed to created DateTimeZone "' . $timeZone . "'", ILogger::DEBUG);
69
+            return new \DateTimeZone($this->getDefaultTimeZone());
70
+        }
71
+    }
72 72
 
73
-	/**
74
-	 * Guess the DateTimeZone for a given offset
75
-	 *
76
-	 * We first try to find a Etc/GMT* timezone, if that does not exist,
77
-	 * we try to find it manually, before falling back to UTC.
78
-	 *
79
-	 * @param mixed $offset
80
-	 * @param bool|int $timestamp
81
-	 * @return \DateTimeZone
82
-	 */
83
-	protected function guessTimeZoneFromOffset($offset, $timestamp) {
84
-		try {
85
-			// Note: the timeZone name is the inverse to the offset,
86
-			// so a positive offset means negative timeZone
87
-			// and the other way around.
88
-			if ($offset > 0) {
89
-				$timeZone = 'Etc/GMT-' . $offset;
90
-			} else {
91
-				$timeZone = 'Etc/GMT+' . abs($offset);
92
-			}
73
+    /**
74
+     * Guess the DateTimeZone for a given offset
75
+     *
76
+     * We first try to find a Etc/GMT* timezone, if that does not exist,
77
+     * we try to find it manually, before falling back to UTC.
78
+     *
79
+     * @param mixed $offset
80
+     * @param bool|int $timestamp
81
+     * @return \DateTimeZone
82
+     */
83
+    protected function guessTimeZoneFromOffset($offset, $timestamp) {
84
+        try {
85
+            // Note: the timeZone name is the inverse to the offset,
86
+            // so a positive offset means negative timeZone
87
+            // and the other way around.
88
+            if ($offset > 0) {
89
+                $timeZone = 'Etc/GMT-' . $offset;
90
+            } else {
91
+                $timeZone = 'Etc/GMT+' . abs($offset);
92
+            }
93 93
 
94
-			return new \DateTimeZone($timeZone);
95
-		} catch (\Exception $e) {
96
-			// If the offset has no Etc/GMT* timezone,
97
-			// we try to guess one timezone that has the same offset
98
-			foreach (\DateTimeZone::listIdentifiers() as $timeZone) {
99
-				$dtz = new \DateTimeZone($timeZone);
100
-				$dateTime = new \DateTime();
94
+            return new \DateTimeZone($timeZone);
95
+        } catch (\Exception $e) {
96
+            // If the offset has no Etc/GMT* timezone,
97
+            // we try to guess one timezone that has the same offset
98
+            foreach (\DateTimeZone::listIdentifiers() as $timeZone) {
99
+                $dtz = new \DateTimeZone($timeZone);
100
+                $dateTime = new \DateTime();
101 101
 
102
-				if ($timestamp !== false) {
103
-					$dateTime->setTimestamp($timestamp);
104
-				}
102
+                if ($timestamp !== false) {
103
+                    $dateTime->setTimestamp($timestamp);
104
+                }
105 105
 
106
-				$dtOffset = $dtz->getOffset($dateTime);
107
-				if ($dtOffset == 3600 * $offset) {
108
-					return $dtz;
109
-				}
110
-			}
106
+                $dtOffset = $dtz->getOffset($dateTime);
107
+                if ($dtOffset == 3600 * $offset) {
108
+                    return $dtz;
109
+                }
110
+            }
111 111
 
112
-			// No timezone found, fallback to UTC
113
-			\OCP\Util::writeLog('datetimezone', 'Failed to find DateTimeZone for offset "' . $offset . "'", ILogger::DEBUG);
114
-			return new \DateTimeZone($this->getDefaultTimeZone());
115
-		}
116
-	}
112
+            // No timezone found, fallback to UTC
113
+            \OCP\Util::writeLog('datetimezone', 'Failed to find DateTimeZone for offset "' . $offset . "'", ILogger::DEBUG);
114
+            return new \DateTimeZone($this->getDefaultTimeZone());
115
+        }
116
+    }
117 117
 
118
-	/**
119
-	 * Get the default timezone of the server
120
-	 *
121
-	 * Falls back to UTC if it is not yet set.
122
-	 *
123
-	 * @return string
124
-	 */
125
-	protected function getDefaultTimeZone() {
126
-		$serverTimeZone = date_default_timezone_get();
127
-		return $serverTimeZone ?: 'UTC';
128
-	}
118
+    /**
119
+     * Get the default timezone of the server
120
+     *
121
+     * Falls back to UTC if it is not yet set.
122
+     *
123
+     * @return string
124
+     */
125
+    protected function getDefaultTimeZone() {
126
+        $serverTimeZone = date_default_timezone_get();
127
+        return $serverTimeZone ?: 'UTC';
128
+    }
129 129
 }
Please login to merge, or discard this patch.
lib/private/Tags.php 2 patches
Indentation   +805 added lines, -805 removed lines patch added patch discarded remove patch
@@ -54,809 +54,809 @@
 block discarded – undo
54 54
 
55 55
 class Tags implements ITags {
56 56
 
57
-	/**
58
-	 * Tags
59
-	 *
60
-	 * @var array
61
-	 */
62
-	private $tags = [];
63
-
64
-	/**
65
-	 * Used for storing objectid/categoryname pairs while rescanning.
66
-	 *
67
-	 * @var array
68
-	 */
69
-	private static $relations = [];
70
-
71
-	/**
72
-	 * Type
73
-	 *
74
-	 * @var string
75
-	 */
76
-	private $type;
77
-
78
-	/**
79
-	 * User
80
-	 *
81
-	 * @var string
82
-	 */
83
-	private $user;
84
-
85
-	/**
86
-	 * Are we including tags for shared items?
87
-	 *
88
-	 * @var bool
89
-	 */
90
-	private $includeShared = false;
91
-
92
-	/**
93
-	 * The current user, plus any owners of the items shared with the current
94
-	 * user, if $this->includeShared === true.
95
-	 *
96
-	 * @var array
97
-	 */
98
-	private $owners = [];
99
-
100
-	/**
101
-	 * The Mapper we're using to communicate our Tag objects to the database.
102
-	 *
103
-	 * @var TagMapper
104
-	 */
105
-	private $mapper;
106
-
107
-	/**
108
-	 * The sharing backend for objects of $this->type. Required if
109
-	 * $this->includeShared === true to determine ownership of items.
110
-	 *
111
-	 * @var \OCP\Share_Backend
112
-	 */
113
-	private $backend;
114
-
115
-	const TAG_TABLE = '*PREFIX*vcategory';
116
-	const RELATION_TABLE = '*PREFIX*vcategory_to_object';
117
-
118
-	/**
119
-	 * Constructor.
120
-	 *
121
-	 * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
122
-	 * @param string $user The user whose data the object will operate on.
123
-	 * @param string $type The type of items for which tags will be loaded.
124
-	 * @param array $defaultTags Tags that should be created at construction.
125
-	 * @param boolean $includeShared Whether to include tags for items shared with this user by others.
126
-	 */
127
-	public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [], $includeShared = false) {
128
-		$this->mapper = $mapper;
129
-		$this->user = $user;
130
-		$this->type = $type;
131
-		$this->includeShared = $includeShared;
132
-		$this->owners = [$this->user];
133
-		if ($this->includeShared) {
134
-			$this->owners = array_merge($this->owners, \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true));
135
-			$this->backend = \OC\Share\Share::getBackend($this->type);
136
-		}
137
-		$this->tags = $this->mapper->loadTags($this->owners, $this->type);
138
-
139
-		if(count($defaultTags) > 0 && count($this->tags) === 0) {
140
-			$this->addMultiple($defaultTags, true);
141
-		}
142
-	}
143
-
144
-	/**
145
-	 * Check if any tags are saved for this type and user.
146
-	 *
147
-	 * @return boolean
148
-	 */
149
-	public function isEmpty() {
150
-		return count($this->tags) === 0;
151
-	}
152
-
153
-	/**
154
-	 * Returns an array mapping a given tag's properties to its values:
155
-	 * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
156
-	 *
157
-	 * @param string $id The ID of the tag that is going to be mapped
158
-	 * @return array|false
159
-	 */
160
-	public function getTag($id) {
161
-		$key = $this->getTagById($id);
162
-		if ($key !== false) {
163
-			return $this->tagMap($this->tags[$key]);
164
-		}
165
-		return false;
166
-	}
167
-
168
-	/**
169
-	 * Get the tags for a specific user.
170
-	 *
171
-	 * This returns an array with maps containing each tag's properties:
172
-	 * [
173
-	 * 	['id' => 0, 'name' = 'First tag', 'owner' = 'User', 'type' => 'tagtype'],
174
-	 * 	['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
175
-	 * ]
176
-	 *
177
-	 * @return array
178
-	 */
179
-	public function getTags() {
180
-		if(!count($this->tags)) {
181
-			return [];
182
-		}
183
-
184
-		usort($this->tags, function ($a, $b) {
185
-			return strnatcasecmp($a->getName(), $b->getName());
186
-		});
187
-		$tagMap = [];
188
-
189
-		foreach($this->tags as $tag) {
190
-			if($tag->getName() !== ITags::TAG_FAVORITE) {
191
-				$tagMap[] = $this->tagMap($tag);
192
-			}
193
-		}
194
-		return $tagMap;
195
-
196
-	}
197
-
198
-	/**
199
-	 * Return only the tags owned by the given user, omitting any tags shared
200
-	 * by other users.
201
-	 *
202
-	 * @param string $user The user whose tags are to be checked.
203
-	 * @return array An array of Tag objects.
204
-	 */
205
-	public function getTagsForUser($user) {
206
-		return array_filter($this->tags,
207
-			function ($tag) use ($user) {
208
-				return $tag->getOwner() === $user;
209
-			}
210
-		);
211
-	}
212
-
213
-	/**
214
-	 * Get the list of tags for the given ids.
215
-	 *
216
-	 * @param array $objIds array of object ids
217
-	 * @return array|boolean of tags id as key to array of tag names
218
-	 * or false if an error occurred
219
-	 */
220
-	public function getTagsForObjects(array $objIds) {
221
-		$entries = [];
222
-
223
-		try {
224
-			$conn = \OC::$server->getDatabaseConnection();
225
-			$chunks = array_chunk($objIds, 900, false);
226
-			foreach ($chunks as $chunk) {
227
-				$result = $conn->executeQuery(
228
-					'SELECT `category`, `categoryid`, `objid` ' .
229
-					'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
230
-					'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231
-					[$this->user, $this->type, $chunk],
232
-					[null, null, IQueryBuilder::PARAM_INT_ARRAY]
233
-				);
234
-				while ($row = $result->fetch()) {
235
-					$objId = (int)$row['objid'];
236
-					if (!isset($entries[$objId])) {
237
-						$entries[$objId] = [];
238
-					}
239
-					$entries[$objId][] = $row['category'];
240
-				}
241
-				if ($result === null) {
242
-					\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243
-					return false;
244
-				}
245
-			}
246
-		} catch(\Exception $e) {
247
-			\OC::$server->getLogger()->logException($e, [
248
-				'message' => __METHOD__,
249
-				'level' => ILogger::ERROR,
250
-				'app' => 'core',
251
-			]);
252
-			return false;
253
-		}
254
-
255
-		return $entries;
256
-	}
257
-
258
-	/**
259
-	 * Get the a list if items tagged with $tag.
260
-	 *
261
-	 * Throws an exception if the tag could not be found.
262
-	 *
263
-	 * @param string $tag Tag id or name.
264
-	 * @return array|false An array of object ids or false on error.
265
-	 * @throws \Exception
266
-	 */
267
-	public function getIdsForTag($tag) {
268
-		$result = null;
269
-		$tagId = false;
270
-		if(is_numeric($tag)) {
271
-			$tagId = $tag;
272
-		} elseif(is_string($tag)) {
273
-			$tag = trim($tag);
274
-			if($tag === '') {
275
-				\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276
-				return false;
277
-			}
278
-			$tagId = $this->getTagId($tag);
279
-		}
280
-
281
-		if($tagId === false) {
282
-			$l10n = \OC::$server->getL10N('core');
283
-			throw new \Exception(
284
-				$l10n->t('Could not find category "%s"', [$tag])
285
-			);
286
-		}
287
-
288
-		$ids = [];
289
-		$sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
290
-			. '` WHERE `categoryid` = ?';
291
-
292
-		try {
293
-			$stmt = \OC_DB::prepare($sql);
294
-			$result = $stmt->execute([$tagId]);
295
-			if ($result === null) {
296
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297
-				return false;
298
-			}
299
-		} catch(\Exception $e) {
300
-			\OC::$server->getLogger()->logException($e, [
301
-				'message' => __METHOD__,
302
-				'level' => ILogger::ERROR,
303
-				'app' => 'core',
304
-			]);
305
-			return false;
306
-		}
307
-
308
-		if(!is_null($result)) {
309
-			while($row = $result->fetchRow()) {
310
-				$id = (int)$row['objid'];
311
-
312
-				if ($this->includeShared) {
313
-					// We have to check if we are really allowed to access the
314
-					// items that are tagged with $tag. To that end, we ask the
315
-					// corresponding sharing backend if the item identified by $id
316
-					// is owned by any of $this->owners.
317
-					foreach ($this->owners as $owner) {
318
-						if ($this->backend->isValidSource($id, $owner)) {
319
-							$ids[] = $id;
320
-							break;
321
-						}
322
-					}
323
-				} else {
324
-					$ids[] = $id;
325
-				}
326
-			}
327
-		}
328
-
329
-		return $ids;
330
-	}
331
-
332
-	/**
333
-	 * Checks whether a tag is saved for the given user,
334
-	 * disregarding the ones shared with him or her.
335
-	 *
336
-	 * @param string $name The tag name to check for.
337
-	 * @param string $user The user whose tags are to be checked.
338
-	 * @return bool
339
-	 */
340
-	public function userHasTag($name, $user) {
341
-		$key = $this->array_searchi($name, $this->getTagsForUser($user));
342
-		return ($key !== false) ? $this->tags[$key]->getId() : false;
343
-	}
344
-
345
-	/**
346
-	 * Checks whether a tag is saved for or shared with the current user.
347
-	 *
348
-	 * @param string $name The tag name to check for.
349
-	 * @return bool
350
-	 */
351
-	public function hasTag($name) {
352
-		return $this->getTagId($name) !== false;
353
-	}
354
-
355
-	/**
356
-	 * Add a new tag.
357
-	 *
358
-	 * @param string $name A string with a name of the tag
359
-	 * @return false|int the id of the added tag or false on error.
360
-	 */
361
-	public function add($name) {
362
-		$name = trim($name);
363
-
364
-		if($name === '') {
365
-			\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366
-			return false;
367
-		}
368
-		if($this->userHasTag($name, $this->user)) {
369
-			\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
370
-			return false;
371
-		}
372
-		try {
373
-			$tag = new Tag($this->user, $this->type, $name);
374
-			$tag = $this->mapper->insert($tag);
375
-			$this->tags[] = $tag;
376
-		} catch(\Exception $e) {
377
-			\OC::$server->getLogger()->logException($e, [
378
-				'message' => __METHOD__,
379
-				'level' => ILogger::ERROR,
380
-				'app' => 'core',
381
-			]);
382
-			return false;
383
-		}
384
-		\OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
385
-		return $tag->getId();
386
-	}
387
-
388
-	/**
389
-	 * Rename tag.
390
-	 *
391
-	 * @param string|integer $from The name or ID of the existing tag
392
-	 * @param string $to The new name of the tag.
393
-	 * @return bool
394
-	 */
395
-	public function rename($from, $to) {
396
-		$from = trim($from);
397
-		$to = trim($to);
398
-
399
-		if($to === '' || $from === '') {
400
-			\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401
-			return false;
402
-		}
403
-
404
-		if (is_numeric($from)) {
405
-			$key = $this->getTagById($from);
406
-		} else {
407
-			$key = $this->getTagByName($from);
408
-		}
409
-		if($key === false) {
410
-			\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
411
-			return false;
412
-		}
413
-		$tag = $this->tags[$key];
414
-
415
-		if($this->userHasTag($to, $tag->getOwner())) {
416
-			\OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
417
-			return false;
418
-		}
419
-
420
-		try {
421
-			$tag->setName($to);
422
-			$this->tags[$key] = $this->mapper->update($tag);
423
-		} catch(\Exception $e) {
424
-			\OC::$server->getLogger()->logException($e, [
425
-				'message' => __METHOD__,
426
-				'level' => ILogger::ERROR,
427
-				'app' => 'core',
428
-			]);
429
-			return false;
430
-		}
431
-		return true;
432
-	}
433
-
434
-	/**
435
-	 * Add a list of new tags.
436
-	 *
437
-	 * @param string[] $names A string with a name or an array of strings containing
438
-	 * the name(s) of the tag(s) to add.
439
-	 * @param bool $sync When true, save the tags
440
-	 * @param int|null $id int Optional object id to add to this|these tag(s)
441
-	 * @return bool Returns false on error.
442
-	 */
443
-	public function addMultiple($names, $sync=false, $id = null) {
444
-		if(!is_array($names)) {
445
-			$names = [$names];
446
-		}
447
-		$names = array_map('trim', $names);
448
-		array_filter($names);
449
-
450
-		$newones = [];
451
-		foreach($names as $name) {
452
-			if(!$this->hasTag($name) && $name !== '') {
453
-				$newones[] = new Tag($this->user, $this->type, $name);
454
-			}
455
-			if(!is_null($id)) {
456
-				// Insert $objectid, $categoryid  pairs if not exist.
457
-				self::$relations[] = ['objid' => $id, 'tag' => $name];
458
-			}
459
-		}
460
-		$this->tags = array_merge($this->tags, $newones);
461
-		if($sync === true) {
462
-			$this->save();
463
-		}
464
-
465
-		return true;
466
-	}
467
-
468
-	/**
469
-	 * Save the list of tags and their object relations
470
-	 */
471
-	protected function save() {
472
-		if(is_array($this->tags)) {
473
-			foreach($this->tags as $tag) {
474
-				try {
475
-					if (!$this->mapper->tagExists($tag)) {
476
-						$this->mapper->insert($tag);
477
-					}
478
-				} catch(\Exception $e) {
479
-					\OC::$server->getLogger()->logException($e, [
480
-						'message' => __METHOD__,
481
-						'level' => ILogger::ERROR,
482
-						'app' => 'core',
483
-					]);
484
-				}
485
-			}
486
-
487
-			// reload tags to get the proper ids.
488
-			$this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
-			\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
490
-				ILogger::DEBUG);
491
-			// Loop through temporarily cached objectid/tagname pairs
492
-			// and save relations.
493
-			$tags = $this->tags;
494
-			// For some reason this is needed or array_search(i) will return 0..?
495
-			ksort($tags);
496
-			$dbConnection = \OC::$server->getDatabaseConnection();
497
-			foreach(self::$relations as $relation) {
498
-				$tagId = $this->getTagId($relation['tag']);
499
-				\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
-				if($tagId) {
501
-					try {
502
-						$dbConnection->insertIfNotExist(self::RELATION_TABLE,
503
-							[
504
-								'objid' => $relation['objid'],
505
-								'categoryid' => $tagId,
506
-								'type' => $this->type,
507
-							]);
508
-					} catch(\Exception $e) {
509
-						\OC::$server->getLogger()->logException($e, [
510
-							'message' => __METHOD__,
511
-							'level' => ILogger::ERROR,
512
-							'app' => 'core',
513
-						]);
514
-					}
515
-				}
516
-			}
517
-			self::$relations = []; // reset
518
-		} else {
519
-			\OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! '
520
-				. print_r($this->tags, true), ILogger::ERROR);
521
-		}
522
-	}
523
-
524
-	/**
525
-	 * Delete tags and tag/object relations for a user.
526
-	 *
527
-	 * For hooking up on post_deleteUser
528
-	 *
529
-	 * @param array $arguments
530
-	 */
531
-	public static function post_deleteUser($arguments) {
532
-		// Find all objectid/tagId pairs.
533
-		$result = null;
534
-		try {
535
-			$stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
536
-				. 'WHERE `uid` = ?');
537
-			$result = $stmt->execute([$arguments['uid']]);
538
-			if ($result === null) {
539
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540
-			}
541
-		} catch(\Exception $e) {
542
-			\OC::$server->getLogger()->logException($e, [
543
-				'message' => __METHOD__,
544
-				'level' => ILogger::ERROR,
545
-				'app' => 'core',
546
-			]);
547
-		}
548
-
549
-		if(!is_null($result)) {
550
-			try {
551
-				$stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
552
-					. 'WHERE `categoryid` = ?');
553
-				while($row = $result->fetchRow()) {
554
-					try {
555
-						$stmt->execute([$row['id']]);
556
-					} catch(\Exception $e) {
557
-						\OC::$server->getLogger()->logException($e, [
558
-							'message' => __METHOD__,
559
-							'level' => ILogger::ERROR,
560
-							'app' => 'core',
561
-						]);
562
-					}
563
-				}
564
-			} catch(\Exception $e) {
565
-				\OC::$server->getLogger()->logException($e, [
566
-					'message' => __METHOD__,
567
-					'level' => ILogger::ERROR,
568
-					'app' => 'core',
569
-				]);
570
-			}
571
-		}
572
-		try {
573
-			$stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
574
-				. 'WHERE `uid` = ?');
575
-			$result = $stmt->execute([$arguments['uid']]);
576
-			if ($result === null) {
577
-				\OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578
-			}
579
-		} catch(\Exception $e) {
580
-			\OC::$server->getLogger()->logException($e, [
581
-				'message' => __METHOD__,
582
-				'level' => ILogger::ERROR,
583
-				'app' => 'core',
584
-			]);
585
-		}
586
-	}
587
-
588
-	/**
589
-	 * Delete tag/object relations from the db
590
-	 *
591
-	 * @param array $ids The ids of the objects
592
-	 * @return boolean Returns false on error.
593
-	 */
594
-	public function purgeObjects(array $ids) {
595
-		if(count($ids) === 0) {
596
-			// job done ;)
597
-			return true;
598
-		}
599
-		$updates = $ids;
600
-		try {
601
-			$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
-			$query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
603
-			$query .= 'AND `type`= ?';
604
-			$updates[] = $this->type;
605
-			$stmt = \OC_DB::prepare($query);
606
-			$result = $stmt->execute($updates);
607
-			if ($result === null) {
608
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609
-				return false;
610
-			}
611
-		} catch(\Exception $e) {
612
-			\OC::$server->getLogger()->logException($e, [
613
-				'message' => __METHOD__,
614
-				'level' => ILogger::ERROR,
615
-				'app' => 'core',
616
-			]);
617
-			return false;
618
-		}
619
-		return true;
620
-	}
621
-
622
-	/**
623
-	 * Get favorites for an object type
624
-	 *
625
-	 * @return array|false An array of object ids.
626
-	 */
627
-	public function getFavorites() {
628
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629
-			return [];
630
-		}
631
-
632
-		try {
633
-			return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
-		} catch(\Exception $e) {
635
-			\OC::$server->getLogger()->logException($e, [
636
-				'message' => __METHOD__,
637
-				'level' => ILogger::ERROR,
638
-				'app' => 'core',
639
-			]);
640
-			return [];
641
-		}
642
-	}
643
-
644
-	/**
645
-	 * Add an object to favorites
646
-	 *
647
-	 * @param int $objid The id of the object
648
-	 * @return boolean
649
-	 */
650
-	public function addToFavorites($objid) {
651
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652
-			$this->add(ITags::TAG_FAVORITE);
653
-		}
654
-		return $this->tagAs($objid, ITags::TAG_FAVORITE);
655
-	}
656
-
657
-	/**
658
-	 * Remove an object from favorites
659
-	 *
660
-	 * @param int $objid The id of the object
661
-	 * @return boolean
662
-	 */
663
-	public function removeFromFavorites($objid) {
664
-		return $this->unTag($objid, ITags::TAG_FAVORITE);
665
-	}
666
-
667
-	/**
668
-	 * Creates a tag/object relation.
669
-	 *
670
-	 * @param int $objid The id of the object
671
-	 * @param string $tag The id or name of the tag
672
-	 * @return boolean Returns false on error.
673
-	 */
674
-	public function tagAs($objid, $tag) {
675
-		if(is_string($tag) && !is_numeric($tag)) {
676
-			$tag = trim($tag);
677
-			if($tag === '') {
678
-				\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679
-				return false;
680
-			}
681
-			if(!$this->hasTag($tag)) {
682
-				$this->add($tag);
683
-			}
684
-			$tagId =  $this->getTagId($tag);
685
-		} else {
686
-			$tagId = $tag;
687
-		}
688
-		try {
689
-			\OC::$server->getDatabaseConnection()->insertIfNotExist(self::RELATION_TABLE,
690
-				[
691
-					'objid' => $objid,
692
-					'categoryid' => $tagId,
693
-					'type' => $this->type,
694
-				]);
695
-		} catch(\Exception $e) {
696
-			\OC::$server->getLogger()->logException($e, [
697
-				'message' => __METHOD__,
698
-				'level' => ILogger::ERROR,
699
-				'app' => 'core',
700
-			]);
701
-			return false;
702
-		}
703
-		return true;
704
-	}
705
-
706
-	/**
707
-	 * Delete single tag/object relation from the db
708
-	 *
709
-	 * @param int $objid The id of the object
710
-	 * @param string $tag The id or name of the tag
711
-	 * @return boolean
712
-	 */
713
-	public function unTag($objid, $tag) {
714
-		if(is_string($tag) && !is_numeric($tag)) {
715
-			$tag = trim($tag);
716
-			if($tag === '') {
717
-				\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718
-				return false;
719
-			}
720
-			$tagId =  $this->getTagId($tag);
721
-		} else {
722
-			$tagId = $tag;
723
-		}
724
-
725
-		try {
726
-			$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
727
-					. 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728
-			$stmt = \OC_DB::prepare($sql);
729
-			$stmt->execute([$objid, $tagId, $this->type]);
730
-		} catch(\Exception $e) {
731
-			\OC::$server->getLogger()->logException($e, [
732
-				'message' => __METHOD__,
733
-				'level' => ILogger::ERROR,
734
-				'app' => 'core',
735
-			]);
736
-			return false;
737
-		}
738
-		return true;
739
-	}
740
-
741
-	/**
742
-	 * Delete tags from the database.
743
-	 *
744
-	 * @param string[]|integer[] $names An array of tags (names or IDs) to delete
745
-	 * @return bool Returns false on error
746
-	 */
747
-	public function delete($names) {
748
-		if(!is_array($names)) {
749
-			$names = [$names];
750
-		}
751
-
752
-		$names = array_map('trim', $names);
753
-		array_filter($names);
754
-
755
-		\OCP\Util::writeLog('core', __METHOD__ . ', before: '
756
-			. print_r($this->tags, true), ILogger::DEBUG);
757
-		foreach($names as $name) {
758
-			$id = null;
759
-
760
-			if (is_numeric($name)) {
761
-				$key = $this->getTagById($name);
762
-			} else {
763
-				$key = $this->getTagByName($name);
764
-			}
765
-			if ($key !== false) {
766
-				$tag = $this->tags[$key];
767
-				$id = $tag->getId();
768
-				unset($this->tags[$key]);
769
-				$this->mapper->delete($tag);
770
-			} else {
771
-				\OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
772
-					. ': not found.', ILogger::ERROR);
773
-			}
774
-			if(!is_null($id) && $id !== false) {
775
-				try {
776
-					$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
777
-							. 'WHERE `categoryid` = ?';
778
-					$stmt = \OC_DB::prepare($sql);
779
-					$result = $stmt->execute([$id]);
780
-					if ($result === null) {
781
-						\OCP\Util::writeLog('core',
782
-							__METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
783
-							ILogger::ERROR);
784
-						return false;
785
-					}
786
-				} catch(\Exception $e) {
787
-					\OC::$server->getLogger()->logException($e, [
788
-						'message' => __METHOD__,
789
-						'level' => ILogger::ERROR,
790
-						'app' => 'core',
791
-					]);
792
-					return false;
793
-				}
794
-			}
795
-		}
796
-		return true;
797
-	}
798
-
799
-	// case-insensitive array_search
800
-	protected function array_searchi($needle, $haystack, $mem='getName') {
801
-		if(!is_array($haystack)) {
802
-			return false;
803
-		}
804
-		return array_search(strtolower($needle), array_map(
805
-			function ($tag) use ($mem) {
806
-				return strtolower(call_user_func([$tag, $mem]));
807
-			}, $haystack)
808
-		);
809
-	}
810
-
811
-	/**
812
-	 * Get a tag's ID.
813
-	 *
814
-	 * @param string $name The tag name to look for.
815
-	 * @return string|bool The tag's id or false if no matching tag is found.
816
-	 */
817
-	private function getTagId($name) {
818
-		$key = $this->array_searchi($name, $this->tags);
819
-		if ($key !== false) {
820
-			return $this->tags[$key]->getId();
821
-		}
822
-		return false;
823
-	}
824
-
825
-	/**
826
-	 * Get a tag by its name.
827
-	 *
828
-	 * @param string $name The tag name.
829
-	 * @return integer|bool The tag object's offset within the $this->tags
830
-	 *                      array or false if it doesn't exist.
831
-	 */
832
-	private function getTagByName($name) {
833
-		return $this->array_searchi($name, $this->tags, 'getName');
834
-	}
835
-
836
-	/**
837
-	 * Get a tag by its ID.
838
-	 *
839
-	 * @param string $id The tag ID to look for.
840
-	 * @return integer|bool The tag object's offset within the $this->tags
841
-	 *                      array or false if it doesn't exist.
842
-	 */
843
-	private function getTagById($id) {
844
-		return $this->array_searchi($id, $this->tags, 'getId');
845
-	}
846
-
847
-	/**
848
-	 * Returns an array mapping a given tag's properties to its values:
849
-	 * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
850
-	 *
851
-	 * @param Tag $tag The tag that is going to be mapped
852
-	 * @return array
853
-	 */
854
-	private function tagMap(Tag $tag) {
855
-		return [
856
-			'id'    => $tag->getId(),
857
-			'name'  => $tag->getName(),
858
-			'owner' => $tag->getOwner(),
859
-			'type'  => $tag->getType()
860
-		];
861
-	}
57
+    /**
58
+     * Tags
59
+     *
60
+     * @var array
61
+     */
62
+    private $tags = [];
63
+
64
+    /**
65
+     * Used for storing objectid/categoryname pairs while rescanning.
66
+     *
67
+     * @var array
68
+     */
69
+    private static $relations = [];
70
+
71
+    /**
72
+     * Type
73
+     *
74
+     * @var string
75
+     */
76
+    private $type;
77
+
78
+    /**
79
+     * User
80
+     *
81
+     * @var string
82
+     */
83
+    private $user;
84
+
85
+    /**
86
+     * Are we including tags for shared items?
87
+     *
88
+     * @var bool
89
+     */
90
+    private $includeShared = false;
91
+
92
+    /**
93
+     * The current user, plus any owners of the items shared with the current
94
+     * user, if $this->includeShared === true.
95
+     *
96
+     * @var array
97
+     */
98
+    private $owners = [];
99
+
100
+    /**
101
+     * The Mapper we're using to communicate our Tag objects to the database.
102
+     *
103
+     * @var TagMapper
104
+     */
105
+    private $mapper;
106
+
107
+    /**
108
+     * The sharing backend for objects of $this->type. Required if
109
+     * $this->includeShared === true to determine ownership of items.
110
+     *
111
+     * @var \OCP\Share_Backend
112
+     */
113
+    private $backend;
114
+
115
+    const TAG_TABLE = '*PREFIX*vcategory';
116
+    const RELATION_TABLE = '*PREFIX*vcategory_to_object';
117
+
118
+    /**
119
+     * Constructor.
120
+     *
121
+     * @param TagMapper $mapper Instance of the TagMapper abstraction layer.
122
+     * @param string $user The user whose data the object will operate on.
123
+     * @param string $type The type of items for which tags will be loaded.
124
+     * @param array $defaultTags Tags that should be created at construction.
125
+     * @param boolean $includeShared Whether to include tags for items shared with this user by others.
126
+     */
127
+    public function __construct(TagMapper $mapper, $user, $type, $defaultTags = [], $includeShared = false) {
128
+        $this->mapper = $mapper;
129
+        $this->user = $user;
130
+        $this->type = $type;
131
+        $this->includeShared = $includeShared;
132
+        $this->owners = [$this->user];
133
+        if ($this->includeShared) {
134
+            $this->owners = array_merge($this->owners, \OC\Share\Share::getSharedItemsOwners($this->user, $this->type, true));
135
+            $this->backend = \OC\Share\Share::getBackend($this->type);
136
+        }
137
+        $this->tags = $this->mapper->loadTags($this->owners, $this->type);
138
+
139
+        if(count($defaultTags) > 0 && count($this->tags) === 0) {
140
+            $this->addMultiple($defaultTags, true);
141
+        }
142
+    }
143
+
144
+    /**
145
+     * Check if any tags are saved for this type and user.
146
+     *
147
+     * @return boolean
148
+     */
149
+    public function isEmpty() {
150
+        return count($this->tags) === 0;
151
+    }
152
+
153
+    /**
154
+     * Returns an array mapping a given tag's properties to its values:
155
+     * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
156
+     *
157
+     * @param string $id The ID of the tag that is going to be mapped
158
+     * @return array|false
159
+     */
160
+    public function getTag($id) {
161
+        $key = $this->getTagById($id);
162
+        if ($key !== false) {
163
+            return $this->tagMap($this->tags[$key]);
164
+        }
165
+        return false;
166
+    }
167
+
168
+    /**
169
+     * Get the tags for a specific user.
170
+     *
171
+     * This returns an array with maps containing each tag's properties:
172
+     * [
173
+     * 	['id' => 0, 'name' = 'First tag', 'owner' = 'User', 'type' => 'tagtype'],
174
+     * 	['id' => 1, 'name' = 'Shared tag', 'owner' = 'Other user', 'type' => 'tagtype'],
175
+     * ]
176
+     *
177
+     * @return array
178
+     */
179
+    public function getTags() {
180
+        if(!count($this->tags)) {
181
+            return [];
182
+        }
183
+
184
+        usort($this->tags, function ($a, $b) {
185
+            return strnatcasecmp($a->getName(), $b->getName());
186
+        });
187
+        $tagMap = [];
188
+
189
+        foreach($this->tags as $tag) {
190
+            if($tag->getName() !== ITags::TAG_FAVORITE) {
191
+                $tagMap[] = $this->tagMap($tag);
192
+            }
193
+        }
194
+        return $tagMap;
195
+
196
+    }
197
+
198
+    /**
199
+     * Return only the tags owned by the given user, omitting any tags shared
200
+     * by other users.
201
+     *
202
+     * @param string $user The user whose tags are to be checked.
203
+     * @return array An array of Tag objects.
204
+     */
205
+    public function getTagsForUser($user) {
206
+        return array_filter($this->tags,
207
+            function ($tag) use ($user) {
208
+                return $tag->getOwner() === $user;
209
+            }
210
+        );
211
+    }
212
+
213
+    /**
214
+     * Get the list of tags for the given ids.
215
+     *
216
+     * @param array $objIds array of object ids
217
+     * @return array|boolean of tags id as key to array of tag names
218
+     * or false if an error occurred
219
+     */
220
+    public function getTagsForObjects(array $objIds) {
221
+        $entries = [];
222
+
223
+        try {
224
+            $conn = \OC::$server->getDatabaseConnection();
225
+            $chunks = array_chunk($objIds, 900, false);
226
+            foreach ($chunks as $chunk) {
227
+                $result = $conn->executeQuery(
228
+                    'SELECT `category`, `categoryid`, `objid` ' .
229
+                    'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
230
+                    'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231
+                    [$this->user, $this->type, $chunk],
232
+                    [null, null, IQueryBuilder::PARAM_INT_ARRAY]
233
+                );
234
+                while ($row = $result->fetch()) {
235
+                    $objId = (int)$row['objid'];
236
+                    if (!isset($entries[$objId])) {
237
+                        $entries[$objId] = [];
238
+                    }
239
+                    $entries[$objId][] = $row['category'];
240
+                }
241
+                if ($result === null) {
242
+                    \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243
+                    return false;
244
+                }
245
+            }
246
+        } catch(\Exception $e) {
247
+            \OC::$server->getLogger()->logException($e, [
248
+                'message' => __METHOD__,
249
+                'level' => ILogger::ERROR,
250
+                'app' => 'core',
251
+            ]);
252
+            return false;
253
+        }
254
+
255
+        return $entries;
256
+    }
257
+
258
+    /**
259
+     * Get the a list if items tagged with $tag.
260
+     *
261
+     * Throws an exception if the tag could not be found.
262
+     *
263
+     * @param string $tag Tag id or name.
264
+     * @return array|false An array of object ids or false on error.
265
+     * @throws \Exception
266
+     */
267
+    public function getIdsForTag($tag) {
268
+        $result = null;
269
+        $tagId = false;
270
+        if(is_numeric($tag)) {
271
+            $tagId = $tag;
272
+        } elseif(is_string($tag)) {
273
+            $tag = trim($tag);
274
+            if($tag === '') {
275
+                \OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276
+                return false;
277
+            }
278
+            $tagId = $this->getTagId($tag);
279
+        }
280
+
281
+        if($tagId === false) {
282
+            $l10n = \OC::$server->getL10N('core');
283
+            throw new \Exception(
284
+                $l10n->t('Could not find category "%s"', [$tag])
285
+            );
286
+        }
287
+
288
+        $ids = [];
289
+        $sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
290
+            . '` WHERE `categoryid` = ?';
291
+
292
+        try {
293
+            $stmt = \OC_DB::prepare($sql);
294
+            $result = $stmt->execute([$tagId]);
295
+            if ($result === null) {
296
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297
+                return false;
298
+            }
299
+        } catch(\Exception $e) {
300
+            \OC::$server->getLogger()->logException($e, [
301
+                'message' => __METHOD__,
302
+                'level' => ILogger::ERROR,
303
+                'app' => 'core',
304
+            ]);
305
+            return false;
306
+        }
307
+
308
+        if(!is_null($result)) {
309
+            while($row = $result->fetchRow()) {
310
+                $id = (int)$row['objid'];
311
+
312
+                if ($this->includeShared) {
313
+                    // We have to check if we are really allowed to access the
314
+                    // items that are tagged with $tag. To that end, we ask the
315
+                    // corresponding sharing backend if the item identified by $id
316
+                    // is owned by any of $this->owners.
317
+                    foreach ($this->owners as $owner) {
318
+                        if ($this->backend->isValidSource($id, $owner)) {
319
+                            $ids[] = $id;
320
+                            break;
321
+                        }
322
+                    }
323
+                } else {
324
+                    $ids[] = $id;
325
+                }
326
+            }
327
+        }
328
+
329
+        return $ids;
330
+    }
331
+
332
+    /**
333
+     * Checks whether a tag is saved for the given user,
334
+     * disregarding the ones shared with him or her.
335
+     *
336
+     * @param string $name The tag name to check for.
337
+     * @param string $user The user whose tags are to be checked.
338
+     * @return bool
339
+     */
340
+    public function userHasTag($name, $user) {
341
+        $key = $this->array_searchi($name, $this->getTagsForUser($user));
342
+        return ($key !== false) ? $this->tags[$key]->getId() : false;
343
+    }
344
+
345
+    /**
346
+     * Checks whether a tag is saved for or shared with the current user.
347
+     *
348
+     * @param string $name The tag name to check for.
349
+     * @return bool
350
+     */
351
+    public function hasTag($name) {
352
+        return $this->getTagId($name) !== false;
353
+    }
354
+
355
+    /**
356
+     * Add a new tag.
357
+     *
358
+     * @param string $name A string with a name of the tag
359
+     * @return false|int the id of the added tag or false on error.
360
+     */
361
+    public function add($name) {
362
+        $name = trim($name);
363
+
364
+        if($name === '') {
365
+            \OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366
+            return false;
367
+        }
368
+        if($this->userHasTag($name, $this->user)) {
369
+            \OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
370
+            return false;
371
+        }
372
+        try {
373
+            $tag = new Tag($this->user, $this->type, $name);
374
+            $tag = $this->mapper->insert($tag);
375
+            $this->tags[] = $tag;
376
+        } catch(\Exception $e) {
377
+            \OC::$server->getLogger()->logException($e, [
378
+                'message' => __METHOD__,
379
+                'level' => ILogger::ERROR,
380
+                'app' => 'core',
381
+            ]);
382
+            return false;
383
+        }
384
+        \OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
385
+        return $tag->getId();
386
+    }
387
+
388
+    /**
389
+     * Rename tag.
390
+     *
391
+     * @param string|integer $from The name or ID of the existing tag
392
+     * @param string $to The new name of the tag.
393
+     * @return bool
394
+     */
395
+    public function rename($from, $to) {
396
+        $from = trim($from);
397
+        $to = trim($to);
398
+
399
+        if($to === '' || $from === '') {
400
+            \OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401
+            return false;
402
+        }
403
+
404
+        if (is_numeric($from)) {
405
+            $key = $this->getTagById($from);
406
+        } else {
407
+            $key = $this->getTagByName($from);
408
+        }
409
+        if($key === false) {
410
+            \OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
411
+            return false;
412
+        }
413
+        $tag = $this->tags[$key];
414
+
415
+        if($this->userHasTag($to, $tag->getOwner())) {
416
+            \OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
417
+            return false;
418
+        }
419
+
420
+        try {
421
+            $tag->setName($to);
422
+            $this->tags[$key] = $this->mapper->update($tag);
423
+        } catch(\Exception $e) {
424
+            \OC::$server->getLogger()->logException($e, [
425
+                'message' => __METHOD__,
426
+                'level' => ILogger::ERROR,
427
+                'app' => 'core',
428
+            ]);
429
+            return false;
430
+        }
431
+        return true;
432
+    }
433
+
434
+    /**
435
+     * Add a list of new tags.
436
+     *
437
+     * @param string[] $names A string with a name or an array of strings containing
438
+     * the name(s) of the tag(s) to add.
439
+     * @param bool $sync When true, save the tags
440
+     * @param int|null $id int Optional object id to add to this|these tag(s)
441
+     * @return bool Returns false on error.
442
+     */
443
+    public function addMultiple($names, $sync=false, $id = null) {
444
+        if(!is_array($names)) {
445
+            $names = [$names];
446
+        }
447
+        $names = array_map('trim', $names);
448
+        array_filter($names);
449
+
450
+        $newones = [];
451
+        foreach($names as $name) {
452
+            if(!$this->hasTag($name) && $name !== '') {
453
+                $newones[] = new Tag($this->user, $this->type, $name);
454
+            }
455
+            if(!is_null($id)) {
456
+                // Insert $objectid, $categoryid  pairs if not exist.
457
+                self::$relations[] = ['objid' => $id, 'tag' => $name];
458
+            }
459
+        }
460
+        $this->tags = array_merge($this->tags, $newones);
461
+        if($sync === true) {
462
+            $this->save();
463
+        }
464
+
465
+        return true;
466
+    }
467
+
468
+    /**
469
+     * Save the list of tags and their object relations
470
+     */
471
+    protected function save() {
472
+        if(is_array($this->tags)) {
473
+            foreach($this->tags as $tag) {
474
+                try {
475
+                    if (!$this->mapper->tagExists($tag)) {
476
+                        $this->mapper->insert($tag);
477
+                    }
478
+                } catch(\Exception $e) {
479
+                    \OC::$server->getLogger()->logException($e, [
480
+                        'message' => __METHOD__,
481
+                        'level' => ILogger::ERROR,
482
+                        'app' => 'core',
483
+                    ]);
484
+                }
485
+            }
486
+
487
+            // reload tags to get the proper ids.
488
+            $this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
+            \OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
490
+                ILogger::DEBUG);
491
+            // Loop through temporarily cached objectid/tagname pairs
492
+            // and save relations.
493
+            $tags = $this->tags;
494
+            // For some reason this is needed or array_search(i) will return 0..?
495
+            ksort($tags);
496
+            $dbConnection = \OC::$server->getDatabaseConnection();
497
+            foreach(self::$relations as $relation) {
498
+                $tagId = $this->getTagId($relation['tag']);
499
+                \OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
+                if($tagId) {
501
+                    try {
502
+                        $dbConnection->insertIfNotExist(self::RELATION_TABLE,
503
+                            [
504
+                                'objid' => $relation['objid'],
505
+                                'categoryid' => $tagId,
506
+                                'type' => $this->type,
507
+                            ]);
508
+                    } catch(\Exception $e) {
509
+                        \OC::$server->getLogger()->logException($e, [
510
+                            'message' => __METHOD__,
511
+                            'level' => ILogger::ERROR,
512
+                            'app' => 'core',
513
+                        ]);
514
+                    }
515
+                }
516
+            }
517
+            self::$relations = []; // reset
518
+        } else {
519
+            \OCP\Util::writeLog('core', __METHOD__.', $this->tags is not an array! '
520
+                . print_r($this->tags, true), ILogger::ERROR);
521
+        }
522
+    }
523
+
524
+    /**
525
+     * Delete tags and tag/object relations for a user.
526
+     *
527
+     * For hooking up on post_deleteUser
528
+     *
529
+     * @param array $arguments
530
+     */
531
+    public static function post_deleteUser($arguments) {
532
+        // Find all objectid/tagId pairs.
533
+        $result = null;
534
+        try {
535
+            $stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
536
+                . 'WHERE `uid` = ?');
537
+            $result = $stmt->execute([$arguments['uid']]);
538
+            if ($result === null) {
539
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540
+            }
541
+        } catch(\Exception $e) {
542
+            \OC::$server->getLogger()->logException($e, [
543
+                'message' => __METHOD__,
544
+                'level' => ILogger::ERROR,
545
+                'app' => 'core',
546
+            ]);
547
+        }
548
+
549
+        if(!is_null($result)) {
550
+            try {
551
+                $stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
552
+                    . 'WHERE `categoryid` = ?');
553
+                while($row = $result->fetchRow()) {
554
+                    try {
555
+                        $stmt->execute([$row['id']]);
556
+                    } catch(\Exception $e) {
557
+                        \OC::$server->getLogger()->logException($e, [
558
+                            'message' => __METHOD__,
559
+                            'level' => ILogger::ERROR,
560
+                            'app' => 'core',
561
+                        ]);
562
+                    }
563
+                }
564
+            } catch(\Exception $e) {
565
+                \OC::$server->getLogger()->logException($e, [
566
+                    'message' => __METHOD__,
567
+                    'level' => ILogger::ERROR,
568
+                    'app' => 'core',
569
+                ]);
570
+            }
571
+        }
572
+        try {
573
+            $stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
574
+                . 'WHERE `uid` = ?');
575
+            $result = $stmt->execute([$arguments['uid']]);
576
+            if ($result === null) {
577
+                \OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578
+            }
579
+        } catch(\Exception $e) {
580
+            \OC::$server->getLogger()->logException($e, [
581
+                'message' => __METHOD__,
582
+                'level' => ILogger::ERROR,
583
+                'app' => 'core',
584
+            ]);
585
+        }
586
+    }
587
+
588
+    /**
589
+     * Delete tag/object relations from the db
590
+     *
591
+     * @param array $ids The ids of the objects
592
+     * @return boolean Returns false on error.
593
+     */
594
+    public function purgeObjects(array $ids) {
595
+        if(count($ids) === 0) {
596
+            // job done ;)
597
+            return true;
598
+        }
599
+        $updates = $ids;
600
+        try {
601
+            $query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
+            $query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
603
+            $query .= 'AND `type`= ?';
604
+            $updates[] = $this->type;
605
+            $stmt = \OC_DB::prepare($query);
606
+            $result = $stmt->execute($updates);
607
+            if ($result === null) {
608
+                \OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609
+                return false;
610
+            }
611
+        } catch(\Exception $e) {
612
+            \OC::$server->getLogger()->logException($e, [
613
+                'message' => __METHOD__,
614
+                'level' => ILogger::ERROR,
615
+                'app' => 'core',
616
+            ]);
617
+            return false;
618
+        }
619
+        return true;
620
+    }
621
+
622
+    /**
623
+     * Get favorites for an object type
624
+     *
625
+     * @return array|false An array of object ids.
626
+     */
627
+    public function getFavorites() {
628
+        if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629
+            return [];
630
+        }
631
+
632
+        try {
633
+            return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
+        } catch(\Exception $e) {
635
+            \OC::$server->getLogger()->logException($e, [
636
+                'message' => __METHOD__,
637
+                'level' => ILogger::ERROR,
638
+                'app' => 'core',
639
+            ]);
640
+            return [];
641
+        }
642
+    }
643
+
644
+    /**
645
+     * Add an object to favorites
646
+     *
647
+     * @param int $objid The id of the object
648
+     * @return boolean
649
+     */
650
+    public function addToFavorites($objid) {
651
+        if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652
+            $this->add(ITags::TAG_FAVORITE);
653
+        }
654
+        return $this->tagAs($objid, ITags::TAG_FAVORITE);
655
+    }
656
+
657
+    /**
658
+     * Remove an object from favorites
659
+     *
660
+     * @param int $objid The id of the object
661
+     * @return boolean
662
+     */
663
+    public function removeFromFavorites($objid) {
664
+        return $this->unTag($objid, ITags::TAG_FAVORITE);
665
+    }
666
+
667
+    /**
668
+     * Creates a tag/object relation.
669
+     *
670
+     * @param int $objid The id of the object
671
+     * @param string $tag The id or name of the tag
672
+     * @return boolean Returns false on error.
673
+     */
674
+    public function tagAs($objid, $tag) {
675
+        if(is_string($tag) && !is_numeric($tag)) {
676
+            $tag = trim($tag);
677
+            if($tag === '') {
678
+                \OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679
+                return false;
680
+            }
681
+            if(!$this->hasTag($tag)) {
682
+                $this->add($tag);
683
+            }
684
+            $tagId =  $this->getTagId($tag);
685
+        } else {
686
+            $tagId = $tag;
687
+        }
688
+        try {
689
+            \OC::$server->getDatabaseConnection()->insertIfNotExist(self::RELATION_TABLE,
690
+                [
691
+                    'objid' => $objid,
692
+                    'categoryid' => $tagId,
693
+                    'type' => $this->type,
694
+                ]);
695
+        } catch(\Exception $e) {
696
+            \OC::$server->getLogger()->logException($e, [
697
+                'message' => __METHOD__,
698
+                'level' => ILogger::ERROR,
699
+                'app' => 'core',
700
+            ]);
701
+            return false;
702
+        }
703
+        return true;
704
+    }
705
+
706
+    /**
707
+     * Delete single tag/object relation from the db
708
+     *
709
+     * @param int $objid The id of the object
710
+     * @param string $tag The id or name of the tag
711
+     * @return boolean
712
+     */
713
+    public function unTag($objid, $tag) {
714
+        if(is_string($tag) && !is_numeric($tag)) {
715
+            $tag = trim($tag);
716
+            if($tag === '') {
717
+                \OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718
+                return false;
719
+            }
720
+            $tagId =  $this->getTagId($tag);
721
+        } else {
722
+            $tagId = $tag;
723
+        }
724
+
725
+        try {
726
+            $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
727
+                    . 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728
+            $stmt = \OC_DB::prepare($sql);
729
+            $stmt->execute([$objid, $tagId, $this->type]);
730
+        } catch(\Exception $e) {
731
+            \OC::$server->getLogger()->logException($e, [
732
+                'message' => __METHOD__,
733
+                'level' => ILogger::ERROR,
734
+                'app' => 'core',
735
+            ]);
736
+            return false;
737
+        }
738
+        return true;
739
+    }
740
+
741
+    /**
742
+     * Delete tags from the database.
743
+     *
744
+     * @param string[]|integer[] $names An array of tags (names or IDs) to delete
745
+     * @return bool Returns false on error
746
+     */
747
+    public function delete($names) {
748
+        if(!is_array($names)) {
749
+            $names = [$names];
750
+        }
751
+
752
+        $names = array_map('trim', $names);
753
+        array_filter($names);
754
+
755
+        \OCP\Util::writeLog('core', __METHOD__ . ', before: '
756
+            . print_r($this->tags, true), ILogger::DEBUG);
757
+        foreach($names as $name) {
758
+            $id = null;
759
+
760
+            if (is_numeric($name)) {
761
+                $key = $this->getTagById($name);
762
+            } else {
763
+                $key = $this->getTagByName($name);
764
+            }
765
+            if ($key !== false) {
766
+                $tag = $this->tags[$key];
767
+                $id = $tag->getId();
768
+                unset($this->tags[$key]);
769
+                $this->mapper->delete($tag);
770
+            } else {
771
+                \OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
772
+                    . ': not found.', ILogger::ERROR);
773
+            }
774
+            if(!is_null($id) && $id !== false) {
775
+                try {
776
+                    $sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
777
+                            . 'WHERE `categoryid` = ?';
778
+                    $stmt = \OC_DB::prepare($sql);
779
+                    $result = $stmt->execute([$id]);
780
+                    if ($result === null) {
781
+                        \OCP\Util::writeLog('core',
782
+                            __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
783
+                            ILogger::ERROR);
784
+                        return false;
785
+                    }
786
+                } catch(\Exception $e) {
787
+                    \OC::$server->getLogger()->logException($e, [
788
+                        'message' => __METHOD__,
789
+                        'level' => ILogger::ERROR,
790
+                        'app' => 'core',
791
+                    ]);
792
+                    return false;
793
+                }
794
+            }
795
+        }
796
+        return true;
797
+    }
798
+
799
+    // case-insensitive array_search
800
+    protected function array_searchi($needle, $haystack, $mem='getName') {
801
+        if(!is_array($haystack)) {
802
+            return false;
803
+        }
804
+        return array_search(strtolower($needle), array_map(
805
+            function ($tag) use ($mem) {
806
+                return strtolower(call_user_func([$tag, $mem]));
807
+            }, $haystack)
808
+        );
809
+    }
810
+
811
+    /**
812
+     * Get a tag's ID.
813
+     *
814
+     * @param string $name The tag name to look for.
815
+     * @return string|bool The tag's id or false if no matching tag is found.
816
+     */
817
+    private function getTagId($name) {
818
+        $key = $this->array_searchi($name, $this->tags);
819
+        if ($key !== false) {
820
+            return $this->tags[$key]->getId();
821
+        }
822
+        return false;
823
+    }
824
+
825
+    /**
826
+     * Get a tag by its name.
827
+     *
828
+     * @param string $name The tag name.
829
+     * @return integer|bool The tag object's offset within the $this->tags
830
+     *                      array or false if it doesn't exist.
831
+     */
832
+    private function getTagByName($name) {
833
+        return $this->array_searchi($name, $this->tags, 'getName');
834
+    }
835
+
836
+    /**
837
+     * Get a tag by its ID.
838
+     *
839
+     * @param string $id The tag ID to look for.
840
+     * @return integer|bool The tag object's offset within the $this->tags
841
+     *                      array or false if it doesn't exist.
842
+     */
843
+    private function getTagById($id) {
844
+        return $this->array_searchi($id, $this->tags, 'getId');
845
+    }
846
+
847
+    /**
848
+     * Returns an array mapping a given tag's properties to its values:
849
+     * ['id' => 0, 'name' = 'Tag', 'owner' = 'User', 'type' => 'tagtype']
850
+     *
851
+     * @param Tag $tag The tag that is going to be mapped
852
+     * @return array
853
+     */
854
+    private function tagMap(Tag $tag) {
855
+        return [
856
+            'id'    => $tag->getId(),
857
+            'name'  => $tag->getName(),
858
+            'owner' => $tag->getOwner(),
859
+            'type'  => $tag->getType()
860
+        ];
861
+    }
862 862
 }
Please login to merge, or discard this patch.
Spacing   +86 added lines, -86 removed lines patch added patch discarded remove patch
@@ -136,7 +136,7 @@  discard block
 block discarded – undo
136 136
 		}
137 137
 		$this->tags = $this->mapper->loadTags($this->owners, $this->type);
138 138
 
139
-		if(count($defaultTags) > 0 && count($this->tags) === 0) {
139
+		if (count($defaultTags) > 0 && count($this->tags) === 0) {
140 140
 			$this->addMultiple($defaultTags, true);
141 141
 		}
142 142
 	}
@@ -177,17 +177,17 @@  discard block
 block discarded – undo
177 177
 	 * @return array
178 178
 	 */
179 179
 	public function getTags() {
180
-		if(!count($this->tags)) {
180
+		if (!count($this->tags)) {
181 181
 			return [];
182 182
 		}
183 183
 
184
-		usort($this->tags, function ($a, $b) {
184
+		usort($this->tags, function($a, $b) {
185 185
 			return strnatcasecmp($a->getName(), $b->getName());
186 186
 		});
187 187
 		$tagMap = [];
188 188
 
189
-		foreach($this->tags as $tag) {
190
-			if($tag->getName() !== ITags::TAG_FAVORITE) {
189
+		foreach ($this->tags as $tag) {
190
+			if ($tag->getName() !== ITags::TAG_FAVORITE) {
191 191
 				$tagMap[] = $this->tagMap($tag);
192 192
 			}
193 193
 		}
@@ -204,7 +204,7 @@  discard block
 block discarded – undo
204 204
 	 */
205 205
 	public function getTagsForUser($user) {
206 206
 		return array_filter($this->tags,
207
-			function ($tag) use ($user) {
207
+			function($tag) use ($user) {
208 208
 				return $tag->getOwner() === $user;
209 209
 			}
210 210
 		);
@@ -225,25 +225,25 @@  discard block
 block discarded – undo
225 225
 			$chunks = array_chunk($objIds, 900, false);
226 226
 			foreach ($chunks as $chunk) {
227 227
 				$result = $conn->executeQuery(
228
-					'SELECT `category`, `categoryid`, `objid` ' .
229
-					'FROM `' . self::RELATION_TABLE . '` r, `' . self::TAG_TABLE . '` ' .
228
+					'SELECT `category`, `categoryid`, `objid` '.
229
+					'FROM `'.self::RELATION_TABLE.'` r, `'.self::TAG_TABLE.'` '.
230 230
 					'WHERE `categoryid` = `id` AND `uid` = ? AND r.`type` = ? AND `objid` IN (?)',
231 231
 					[$this->user, $this->type, $chunk],
232 232
 					[null, null, IQueryBuilder::PARAM_INT_ARRAY]
233 233
 				);
234 234
 				while ($row = $result->fetch()) {
235
-					$objId = (int)$row['objid'];
235
+					$objId = (int) $row['objid'];
236 236
 					if (!isset($entries[$objId])) {
237 237
 						$entries[$objId] = [];
238 238
 					}
239 239
 					$entries[$objId][] = $row['category'];
240 240
 				}
241 241
 				if ($result === null) {
242
-					\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
242
+					\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
243 243
 					return false;
244 244
 				}
245 245
 			}
246
-		} catch(\Exception $e) {
246
+		} catch (\Exception $e) {
247 247
 			\OC::$server->getLogger()->logException($e, [
248 248
 				'message' => __METHOD__,
249 249
 				'level' => ILogger::ERROR,
@@ -267,18 +267,18 @@  discard block
 block discarded – undo
267 267
 	public function getIdsForTag($tag) {
268 268
 		$result = null;
269 269
 		$tagId = false;
270
-		if(is_numeric($tag)) {
270
+		if (is_numeric($tag)) {
271 271
 			$tagId = $tag;
272
-		} elseif(is_string($tag)) {
272
+		} elseif (is_string($tag)) {
273 273
 			$tag = trim($tag);
274
-			if($tag === '') {
274
+			if ($tag === '') {
275 275
 				\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
276 276
 				return false;
277 277
 			}
278 278
 			$tagId = $this->getTagId($tag);
279 279
 		}
280 280
 
281
-		if($tagId === false) {
281
+		if ($tagId === false) {
282 282
 			$l10n = \OC::$server->getL10N('core');
283 283
 			throw new \Exception(
284 284
 				$l10n->t('Could not find category "%s"', [$tag])
@@ -286,17 +286,17 @@  discard block
 block discarded – undo
286 286
 		}
287 287
 
288 288
 		$ids = [];
289
-		$sql = 'SELECT `objid` FROM `' . self::RELATION_TABLE
289
+		$sql = 'SELECT `objid` FROM `'.self::RELATION_TABLE
290 290
 			. '` WHERE `categoryid` = ?';
291 291
 
292 292
 		try {
293 293
 			$stmt = \OC_DB::prepare($sql);
294 294
 			$result = $stmt->execute([$tagId]);
295 295
 			if ($result === null) {
296
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
296
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
297 297
 				return false;
298 298
 			}
299
-		} catch(\Exception $e) {
299
+		} catch (\Exception $e) {
300 300
 			\OC::$server->getLogger()->logException($e, [
301 301
 				'message' => __METHOD__,
302 302
 				'level' => ILogger::ERROR,
@@ -305,9 +305,9 @@  discard block
 block discarded – undo
305 305
 			return false;
306 306
 		}
307 307
 
308
-		if(!is_null($result)) {
309
-			while($row = $result->fetchRow()) {
310
-				$id = (int)$row['objid'];
308
+		if (!is_null($result)) {
309
+			while ($row = $result->fetchRow()) {
310
+				$id = (int) $row['objid'];
311 311
 
312 312
 				if ($this->includeShared) {
313 313
 					// We have to check if we are really allowed to access the
@@ -361,19 +361,19 @@  discard block
 block discarded – undo
361 361
 	public function add($name) {
362 362
 		$name = trim($name);
363 363
 
364
-		if($name === '') {
364
+		if ($name === '') {
365 365
 			\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
366 366
 			return false;
367 367
 		}
368
-		if($this->userHasTag($name, $this->user)) {
369
-			\OCP\Util::writeLog('core', __METHOD__.', name: ' . $name. ' exists already', ILogger::DEBUG);
368
+		if ($this->userHasTag($name, $this->user)) {
369
+			\OCP\Util::writeLog('core', __METHOD__.', name: '.$name.' exists already', ILogger::DEBUG);
370 370
 			return false;
371 371
 		}
372 372
 		try {
373 373
 			$tag = new Tag($this->user, $this->type, $name);
374 374
 			$tag = $this->mapper->insert($tag);
375 375
 			$this->tags[] = $tag;
376
-		} catch(\Exception $e) {
376
+		} catch (\Exception $e) {
377 377
 			\OC::$server->getLogger()->logException($e, [
378 378
 				'message' => __METHOD__,
379 379
 				'level' => ILogger::ERROR,
@@ -381,7 +381,7 @@  discard block
 block discarded – undo
381 381
 			]);
382 382
 			return false;
383 383
 		}
384
-		\OCP\Util::writeLog('core', __METHOD__.', id: ' . $tag->getId(), ILogger::DEBUG);
384
+		\OCP\Util::writeLog('core', __METHOD__.', id: '.$tag->getId(), ILogger::DEBUG);
385 385
 		return $tag->getId();
386 386
 	}
387 387
 
@@ -396,7 +396,7 @@  discard block
 block discarded – undo
396 396
 		$from = trim($from);
397 397
 		$to = trim($to);
398 398
 
399
-		if($to === '' || $from === '') {
399
+		if ($to === '' || $from === '') {
400 400
 			\OCP\Util::writeLog('core', __METHOD__.', Cannot use empty tag names', ILogger::DEBUG);
401 401
 			return false;
402 402
 		}
@@ -406,21 +406,21 @@  discard block
 block discarded – undo
406 406
 		} else {
407 407
 			$key = $this->getTagByName($from);
408 408
 		}
409
-		if($key === false) {
410
-			\OCP\Util::writeLog('core', __METHOD__.', tag: ' . $from. ' does not exist', ILogger::DEBUG);
409
+		if ($key === false) {
410
+			\OCP\Util::writeLog('core', __METHOD__.', tag: '.$from.' does not exist', ILogger::DEBUG);
411 411
 			return false;
412 412
 		}
413 413
 		$tag = $this->tags[$key];
414 414
 
415
-		if($this->userHasTag($to, $tag->getOwner())) {
416
-			\OCP\Util::writeLog('core', __METHOD__.', A tag named ' . $to. ' already exists for user ' . $tag->getOwner() . '.', ILogger::DEBUG);
415
+		if ($this->userHasTag($to, $tag->getOwner())) {
416
+			\OCP\Util::writeLog('core', __METHOD__.', A tag named '.$to.' already exists for user '.$tag->getOwner().'.', ILogger::DEBUG);
417 417
 			return false;
418 418
 		}
419 419
 
420 420
 		try {
421 421
 			$tag->setName($to);
422 422
 			$this->tags[$key] = $this->mapper->update($tag);
423
-		} catch(\Exception $e) {
423
+		} catch (\Exception $e) {
424 424
 			\OC::$server->getLogger()->logException($e, [
425 425
 				'message' => __METHOD__,
426 426
 				'level' => ILogger::ERROR,
@@ -440,25 +440,25 @@  discard block
 block discarded – undo
440 440
 	 * @param int|null $id int Optional object id to add to this|these tag(s)
441 441
 	 * @return bool Returns false on error.
442 442
 	 */
443
-	public function addMultiple($names, $sync=false, $id = null) {
444
-		if(!is_array($names)) {
443
+	public function addMultiple($names, $sync = false, $id = null) {
444
+		if (!is_array($names)) {
445 445
 			$names = [$names];
446 446
 		}
447 447
 		$names = array_map('trim', $names);
448 448
 		array_filter($names);
449 449
 
450 450
 		$newones = [];
451
-		foreach($names as $name) {
452
-			if(!$this->hasTag($name) && $name !== '') {
451
+		foreach ($names as $name) {
452
+			if (!$this->hasTag($name) && $name !== '') {
453 453
 				$newones[] = new Tag($this->user, $this->type, $name);
454 454
 			}
455
-			if(!is_null($id)) {
455
+			if (!is_null($id)) {
456 456
 				// Insert $objectid, $categoryid  pairs if not exist.
457 457
 				self::$relations[] = ['objid' => $id, 'tag' => $name];
458 458
 			}
459 459
 		}
460 460
 		$this->tags = array_merge($this->tags, $newones);
461
-		if($sync === true) {
461
+		if ($sync === true) {
462 462
 			$this->save();
463 463
 		}
464 464
 
@@ -469,13 +469,13 @@  discard block
 block discarded – undo
469 469
 	 * Save the list of tags and their object relations
470 470
 	 */
471 471
 	protected function save() {
472
-		if(is_array($this->tags)) {
473
-			foreach($this->tags as $tag) {
472
+		if (is_array($this->tags)) {
473
+			foreach ($this->tags as $tag) {
474 474
 				try {
475 475
 					if (!$this->mapper->tagExists($tag)) {
476 476
 						$this->mapper->insert($tag);
477 477
 					}
478
-				} catch(\Exception $e) {
478
+				} catch (\Exception $e) {
479 479
 					\OC::$server->getLogger()->logException($e, [
480 480
 						'message' => __METHOD__,
481 481
 						'level' => ILogger::ERROR,
@@ -486,7 +486,7 @@  discard block
 block discarded – undo
486 486
 
487 487
 			// reload tags to get the proper ids.
488 488
 			$this->tags = $this->mapper->loadTags($this->owners, $this->type);
489
-			\OCP\Util::writeLog('core', __METHOD__.', tags: ' . print_r($this->tags, true),
489
+			\OCP\Util::writeLog('core', __METHOD__.', tags: '.print_r($this->tags, true),
490 490
 				ILogger::DEBUG);
491 491
 			// Loop through temporarily cached objectid/tagname pairs
492 492
 			// and save relations.
@@ -494,10 +494,10 @@  discard block
 block discarded – undo
494 494
 			// For some reason this is needed or array_search(i) will return 0..?
495 495
 			ksort($tags);
496 496
 			$dbConnection = \OC::$server->getDatabaseConnection();
497
-			foreach(self::$relations as $relation) {
497
+			foreach (self::$relations as $relation) {
498 498
 				$tagId = $this->getTagId($relation['tag']);
499
-				\OCP\Util::writeLog('core', __METHOD__ . 'catid, ' . $relation['tag'] . ' ' . $tagId, ILogger::DEBUG);
500
-				if($tagId) {
499
+				\OCP\Util::writeLog('core', __METHOD__.'catid, '.$relation['tag'].' '.$tagId, ILogger::DEBUG);
500
+				if ($tagId) {
501 501
 					try {
502 502
 						$dbConnection->insertIfNotExist(self::RELATION_TABLE,
503 503
 							[
@@ -505,7 +505,7 @@  discard block
 block discarded – undo
505 505
 								'categoryid' => $tagId,
506 506
 								'type' => $this->type,
507 507
 							]);
508
-					} catch(\Exception $e) {
508
+					} catch (\Exception $e) {
509 509
 						\OC::$server->getLogger()->logException($e, [
510 510
 							'message' => __METHOD__,
511 511
 							'level' => ILogger::ERROR,
@@ -532,13 +532,13 @@  discard block
 block discarded – undo
532 532
 		// Find all objectid/tagId pairs.
533 533
 		$result = null;
534 534
 		try {
535
-			$stmt = \OC_DB::prepare('SELECT `id` FROM `' . self::TAG_TABLE . '` '
535
+			$stmt = \OC_DB::prepare('SELECT `id` FROM `'.self::TAG_TABLE.'` '
536 536
 				. 'WHERE `uid` = ?');
537 537
 			$result = $stmt->execute([$arguments['uid']]);
538 538
 			if ($result === null) {
539
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
539
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
540 540
 			}
541
-		} catch(\Exception $e) {
541
+		} catch (\Exception $e) {
542 542
 			\OC::$server->getLogger()->logException($e, [
543 543
 				'message' => __METHOD__,
544 544
 				'level' => ILogger::ERROR,
@@ -546,14 +546,14 @@  discard block
 block discarded – undo
546 546
 			]);
547 547
 		}
548 548
 
549
-		if(!is_null($result)) {
549
+		if (!is_null($result)) {
550 550
 			try {
551
-				$stmt = \OC_DB::prepare('DELETE FROM `' . self::RELATION_TABLE . '` '
551
+				$stmt = \OC_DB::prepare('DELETE FROM `'.self::RELATION_TABLE.'` '
552 552
 					. 'WHERE `categoryid` = ?');
553
-				while($row = $result->fetchRow()) {
553
+				while ($row = $result->fetchRow()) {
554 554
 					try {
555 555
 						$stmt->execute([$row['id']]);
556
-					} catch(\Exception $e) {
556
+					} catch (\Exception $e) {
557 557
 						\OC::$server->getLogger()->logException($e, [
558 558
 							'message' => __METHOD__,
559 559
 							'level' => ILogger::ERROR,
@@ -561,7 +561,7 @@  discard block
 block discarded – undo
561 561
 						]);
562 562
 					}
563 563
 				}
564
-			} catch(\Exception $e) {
564
+			} catch (\Exception $e) {
565 565
 				\OC::$server->getLogger()->logException($e, [
566 566
 					'message' => __METHOD__,
567 567
 					'level' => ILogger::ERROR,
@@ -570,13 +570,13 @@  discard block
 block discarded – undo
570 570
 			}
571 571
 		}
572 572
 		try {
573
-			$stmt = \OC_DB::prepare('DELETE FROM `' . self::TAG_TABLE . '` '
573
+			$stmt = \OC_DB::prepare('DELETE FROM `'.self::TAG_TABLE.'` '
574 574
 				. 'WHERE `uid` = ?');
575 575
 			$result = $stmt->execute([$arguments['uid']]);
576 576
 			if ($result === null) {
577
-				\OCP\Util::writeLog('core', __METHOD__. ', DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
577
+				\OCP\Util::writeLog('core', __METHOD__.', DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
578 578
 			}
579
-		} catch(\Exception $e) {
579
+		} catch (\Exception $e) {
580 580
 			\OC::$server->getLogger()->logException($e, [
581 581
 				'message' => __METHOD__,
582 582
 				'level' => ILogger::ERROR,
@@ -592,23 +592,23 @@  discard block
 block discarded – undo
592 592
 	 * @return boolean Returns false on error.
593 593
 	 */
594 594
 	public function purgeObjects(array $ids) {
595
-		if(count($ids) === 0) {
595
+		if (count($ids) === 0) {
596 596
 			// job done ;)
597 597
 			return true;
598 598
 		}
599 599
 		$updates = $ids;
600 600
 		try {
601
-			$query = 'DELETE FROM `' . self::RELATION_TABLE . '` ';
602
-			$query .= 'WHERE `objid` IN (' . str_repeat('?,', count($ids)-1) . '?) ';
601
+			$query = 'DELETE FROM `'.self::RELATION_TABLE.'` ';
602
+			$query .= 'WHERE `objid` IN ('.str_repeat('?,', count($ids) - 1).'?) ';
603 603
 			$query .= 'AND `type`= ?';
604 604
 			$updates[] = $this->type;
605 605
 			$stmt = \OC_DB::prepare($query);
606 606
 			$result = $stmt->execute($updates);
607 607
 			if ($result === null) {
608
-				\OCP\Util::writeLog('core', __METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
608
+				\OCP\Util::writeLog('core', __METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(), ILogger::ERROR);
609 609
 				return false;
610 610
 			}
611
-		} catch(\Exception $e) {
611
+		} catch (\Exception $e) {
612 612
 			\OC::$server->getLogger()->logException($e, [
613 613
 				'message' => __METHOD__,
614 614
 				'level' => ILogger::ERROR,
@@ -625,13 +625,13 @@  discard block
 block discarded – undo
625 625
 	 * @return array|false An array of object ids.
626 626
 	 */
627 627
 	public function getFavorites() {
628
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
628
+		if (!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
629 629
 			return [];
630 630
 		}
631 631
 
632 632
 		try {
633 633
 			return $this->getIdsForTag(ITags::TAG_FAVORITE);
634
-		} catch(\Exception $e) {
634
+		} catch (\Exception $e) {
635 635
 			\OC::$server->getLogger()->logException($e, [
636 636
 				'message' => __METHOD__,
637 637
 				'level' => ILogger::ERROR,
@@ -648,7 +648,7 @@  discard block
 block discarded – undo
648 648
 	 * @return boolean
649 649
 	 */
650 650
 	public function addToFavorites($objid) {
651
-		if(!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
651
+		if (!$this->userHasTag(ITags::TAG_FAVORITE, $this->user)) {
652 652
 			$this->add(ITags::TAG_FAVORITE);
653 653
 		}
654 654
 		return $this->tagAs($objid, ITags::TAG_FAVORITE);
@@ -672,16 +672,16 @@  discard block
 block discarded – undo
672 672
 	 * @return boolean Returns false on error.
673 673
 	 */
674 674
 	public function tagAs($objid, $tag) {
675
-		if(is_string($tag) && !is_numeric($tag)) {
675
+		if (is_string($tag) && !is_numeric($tag)) {
676 676
 			$tag = trim($tag);
677
-			if($tag === '') {
677
+			if ($tag === '') {
678 678
 				\OCP\Util::writeLog('core', __METHOD__.', Cannot add an empty tag', ILogger::DEBUG);
679 679
 				return false;
680 680
 			}
681
-			if(!$this->hasTag($tag)) {
681
+			if (!$this->hasTag($tag)) {
682 682
 				$this->add($tag);
683 683
 			}
684
-			$tagId =  $this->getTagId($tag);
684
+			$tagId = $this->getTagId($tag);
685 685
 		} else {
686 686
 			$tagId = $tag;
687 687
 		}
@@ -692,7 +692,7 @@  discard block
 block discarded – undo
692 692
 					'categoryid' => $tagId,
693 693
 					'type' => $this->type,
694 694
 				]);
695
-		} catch(\Exception $e) {
695
+		} catch (\Exception $e) {
696 696
 			\OC::$server->getLogger()->logException($e, [
697 697
 				'message' => __METHOD__,
698 698
 				'level' => ILogger::ERROR,
@@ -711,23 +711,23 @@  discard block
 block discarded – undo
711 711
 	 * @return boolean
712 712
 	 */
713 713
 	public function unTag($objid, $tag) {
714
-		if(is_string($tag) && !is_numeric($tag)) {
714
+		if (is_string($tag) && !is_numeric($tag)) {
715 715
 			$tag = trim($tag);
716
-			if($tag === '') {
716
+			if ($tag === '') {
717 717
 				\OCP\Util::writeLog('core', __METHOD__.', Tag name is empty', ILogger::DEBUG);
718 718
 				return false;
719 719
 			}
720
-			$tagId =  $this->getTagId($tag);
720
+			$tagId = $this->getTagId($tag);
721 721
 		} else {
722 722
 			$tagId = $tag;
723 723
 		}
724 724
 
725 725
 		try {
726
-			$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
726
+			$sql = 'DELETE FROM `'.self::RELATION_TABLE.'` '
727 727
 					. 'WHERE `objid` = ? AND `categoryid` = ? AND `type` = ?';
728 728
 			$stmt = \OC_DB::prepare($sql);
729 729
 			$stmt->execute([$objid, $tagId, $this->type]);
730
-		} catch(\Exception $e) {
730
+		} catch (\Exception $e) {
731 731
 			\OC::$server->getLogger()->logException($e, [
732 732
 				'message' => __METHOD__,
733 733
 				'level' => ILogger::ERROR,
@@ -745,16 +745,16 @@  discard block
 block discarded – undo
745 745
 	 * @return bool Returns false on error
746 746
 	 */
747 747
 	public function delete($names) {
748
-		if(!is_array($names)) {
748
+		if (!is_array($names)) {
749 749
 			$names = [$names];
750 750
 		}
751 751
 
752 752
 		$names = array_map('trim', $names);
753 753
 		array_filter($names);
754 754
 
755
-		\OCP\Util::writeLog('core', __METHOD__ . ', before: '
755
+		\OCP\Util::writeLog('core', __METHOD__.', before: '
756 756
 			. print_r($this->tags, true), ILogger::DEBUG);
757
-		foreach($names as $name) {
757
+		foreach ($names as $name) {
758 758
 			$id = null;
759 759
 
760 760
 			if (is_numeric($name)) {
@@ -768,22 +768,22 @@  discard block
 block discarded – undo
768 768
 				unset($this->tags[$key]);
769 769
 				$this->mapper->delete($tag);
770 770
 			} else {
771
-				\OCP\Util::writeLog('core', __METHOD__ . 'Cannot delete tag ' . $name
771
+				\OCP\Util::writeLog('core', __METHOD__.'Cannot delete tag '.$name
772 772
 					. ': not found.', ILogger::ERROR);
773 773
 			}
774
-			if(!is_null($id) && $id !== false) {
774
+			if (!is_null($id) && $id !== false) {
775 775
 				try {
776
-					$sql = 'DELETE FROM `' . self::RELATION_TABLE . '` '
776
+					$sql = 'DELETE FROM `'.self::RELATION_TABLE.'` '
777 777
 							. 'WHERE `categoryid` = ?';
778 778
 					$stmt = \OC_DB::prepare($sql);
779 779
 					$result = $stmt->execute([$id]);
780 780
 					if ($result === null) {
781 781
 						\OCP\Util::writeLog('core',
782
-							__METHOD__. 'DB error: ' . \OC::$server->getDatabaseConnection()->getError(),
782
+							__METHOD__.'DB error: '.\OC::$server->getDatabaseConnection()->getError(),
783 783
 							ILogger::ERROR);
784 784
 						return false;
785 785
 					}
786
-				} catch(\Exception $e) {
786
+				} catch (\Exception $e) {
787 787
 					\OC::$server->getLogger()->logException($e, [
788 788
 						'message' => __METHOD__,
789 789
 						'level' => ILogger::ERROR,
@@ -797,12 +797,12 @@  discard block
 block discarded – undo
797 797
 	}
798 798
 
799 799
 	// case-insensitive array_search
800
-	protected function array_searchi($needle, $haystack, $mem='getName') {
801
-		if(!is_array($haystack)) {
800
+	protected function array_searchi($needle, $haystack, $mem = 'getName') {
801
+		if (!is_array($haystack)) {
802 802
 			return false;
803 803
 		}
804 804
 		return array_search(strtolower($needle), array_map(
805
-			function ($tag) use ($mem) {
805
+			function($tag) use ($mem) {
806 806
 				return strtolower(call_user_func([$tag, $mem]));
807 807
 			}, $haystack)
808 808
 		);
Please login to merge, or discard this patch.
lib/private/Collaboration/Collaborators/RemotePlugin.php 2 patches
Indentation   +140 added lines, -140 removed lines patch added patch discarded remove patch
@@ -37,155 +37,155 @@
 block discarded – undo
37 37
 use OCP\Share;
38 38
 
39 39
 class RemotePlugin implements ISearchPlugin {
40
-	protected $shareeEnumeration;
40
+    protected $shareeEnumeration;
41 41
 
42
-	/** @var IManager */
43
-	private $contactsManager;
44
-	/** @var ICloudIdManager */
45
-	private $cloudIdManager;
46
-	/** @var IConfig */
47
-	private $config;
48
-	/** @var IUserManager */
49
-	private $userManager;
50
-	/** @var string */
51
-	private $userId = '';
42
+    /** @var IManager */
43
+    private $contactsManager;
44
+    /** @var ICloudIdManager */
45
+    private $cloudIdManager;
46
+    /** @var IConfig */
47
+    private $config;
48
+    /** @var IUserManager */
49
+    private $userManager;
50
+    /** @var string */
51
+    private $userId = '';
52 52
 
53
-	public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
54
-		$this->contactsManager = $contactsManager;
55
-		$this->cloudIdManager = $cloudIdManager;
56
-		$this->config = $config;
57
-		$this->userManager = $userManager;
58
-		$user = $userSession->getUser();
59
-		if ($user !== null) {
60
-			$this->userId = $user->getUID();
61
-		}
62
-		$this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
63
-	}
53
+    public function __construct(IManager $contactsManager, ICloudIdManager $cloudIdManager, IConfig $config, IUserManager $userManager, IUserSession $userSession) {
54
+        $this->contactsManager = $contactsManager;
55
+        $this->cloudIdManager = $cloudIdManager;
56
+        $this->config = $config;
57
+        $this->userManager = $userManager;
58
+        $user = $userSession->getUser();
59
+        if ($user !== null) {
60
+            $this->userId = $user->getUID();
61
+        }
62
+        $this->shareeEnumeration = $this->config->getAppValue('core', 'shareapi_allow_share_dialog_user_enumeration', 'yes') === 'yes';
63
+    }
64 64
 
65
-	public function search($search, $limit, $offset, ISearchResult $searchResult) {
66
-		$result = ['wide' => [], 'exact' => []];
67
-		$resultType = new SearchResultType('remotes');
65
+    public function search($search, $limit, $offset, ISearchResult $searchResult) {
66
+        $result = ['wide' => [], 'exact' => []];
67
+        $resultType = new SearchResultType('remotes');
68 68
 
69
-		// Search in contacts
70
-		//@todo Pagination missing
71
-		$addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
72
-		foreach ($addressBookContacts as $contact) {
73
-			if (isset($contact['isLocalSystemBook'])) {
74
-				continue;
75
-			}
76
-			if (isset($contact['CLOUD'])) {
77
-				$cloudIds = $contact['CLOUD'];
78
-				if (is_string($cloudIds)) {
79
-					$cloudIds = [$cloudIds];
80
-				}
81
-				$lowerSearch = strtolower($search);
82
-				foreach ($cloudIds as $cloudId) {
83
-					$cloudIdType = '';
84
-					if (\is_array($cloudId)) {
85
-						$cloudIdData = $cloudId;
86
-						$cloudId = $cloudIdData['value'];
87
-						$cloudIdType = $cloudIdData['type'];
88
-					}
89
-					try {
90
-						list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
91
-					} catch (\InvalidArgumentException $e) {
92
-						continue;
93
-					}
69
+        // Search in contacts
70
+        //@todo Pagination missing
71
+        $addressBookContacts = $this->contactsManager->search($search, ['CLOUD', 'FN']);
72
+        foreach ($addressBookContacts as $contact) {
73
+            if (isset($contact['isLocalSystemBook'])) {
74
+                continue;
75
+            }
76
+            if (isset($contact['CLOUD'])) {
77
+                $cloudIds = $contact['CLOUD'];
78
+                if (is_string($cloudIds)) {
79
+                    $cloudIds = [$cloudIds];
80
+                }
81
+                $lowerSearch = strtolower($search);
82
+                foreach ($cloudIds as $cloudId) {
83
+                    $cloudIdType = '';
84
+                    if (\is_array($cloudId)) {
85
+                        $cloudIdData = $cloudId;
86
+                        $cloudId = $cloudIdData['value'];
87
+                        $cloudIdType = $cloudIdData['type'];
88
+                    }
89
+                    try {
90
+                        list($remoteUser, $serverUrl) = $this->splitUserRemote($cloudId);
91
+                    } catch (\InvalidArgumentException $e) {
92
+                        continue;
93
+                    }
94 94
 
95
-					$localUser = $this->userManager->get($remoteUser);
96
-					/**
97
-					 * Add local share if remote cloud id matches a local user ones
98
-					 */
99
-					if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
100
-						$result['wide'][] = [
101
-							'label' => $contact['FN'],
102
-							'uuid' => $contact['UID'],
103
-							'value' => [
104
-								'shareType' => Share::SHARE_TYPE_USER,
105
-								'shareWith' => $remoteUser
106
-							]
107
-						];
108
-					}
95
+                    $localUser = $this->userManager->get($remoteUser);
96
+                    /**
97
+                     * Add local share if remote cloud id matches a local user ones
98
+                     */
99
+                    if ($localUser !== null && $remoteUser !== $this->userId && $cloudId === $localUser->getCloudId()) {
100
+                        $result['wide'][] = [
101
+                            'label' => $contact['FN'],
102
+                            'uuid' => $contact['UID'],
103
+                            'value' => [
104
+                                'shareType' => Share::SHARE_TYPE_USER,
105
+                                'shareWith' => $remoteUser
106
+                            ]
107
+                        ];
108
+                    }
109 109
 
110
-					if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
111
-						if (strtolower($cloudId) === $lowerSearch) {
112
-							$searchResult->markExactIdMatch($resultType);
113
-						}
114
-						$result['exact'][] = [
115
-							'label' => $contact['FN'] . " ($cloudId)",
116
-							'uuid' => $contact['UID'],
117
-							'name' => $contact['FN'],
118
-							'type' => $cloudIdType,
119
-							'value' => [
120
-								'shareType' => Share::SHARE_TYPE_REMOTE,
121
-								'shareWith' => $cloudId,
122
-								'server' => $serverUrl,
123
-							],
124
-						];
125
-					} else {
126
-						$result['wide'][] = [
127
-							'label' => $contact['FN'] . " ($cloudId)",
128
-							'uuid' => $contact['UID'],
129
-							'name' => $contact['FN'],
130
-							'type' => $cloudIdType,
131
-							'value' => [
132
-								'shareType' => Share::SHARE_TYPE_REMOTE,
133
-								'shareWith' => $cloudId,
134
-								'server' => $serverUrl,
135
-							],
136
-						];
137
-					}
138
-				}
139
-			}
140
-		}
110
+                    if (strtolower($contact['FN']) === $lowerSearch || strtolower($cloudId) === $lowerSearch) {
111
+                        if (strtolower($cloudId) === $lowerSearch) {
112
+                            $searchResult->markExactIdMatch($resultType);
113
+                        }
114
+                        $result['exact'][] = [
115
+                            'label' => $contact['FN'] . " ($cloudId)",
116
+                            'uuid' => $contact['UID'],
117
+                            'name' => $contact['FN'],
118
+                            'type' => $cloudIdType,
119
+                            'value' => [
120
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
121
+                                'shareWith' => $cloudId,
122
+                                'server' => $serverUrl,
123
+                            ],
124
+                        ];
125
+                    } else {
126
+                        $result['wide'][] = [
127
+                            'label' => $contact['FN'] . " ($cloudId)",
128
+                            'uuid' => $contact['UID'],
129
+                            'name' => $contact['FN'],
130
+                            'type' => $cloudIdType,
131
+                            'value' => [
132
+                                'shareType' => Share::SHARE_TYPE_REMOTE,
133
+                                'shareWith' => $cloudId,
134
+                                'server' => $serverUrl,
135
+                            ],
136
+                        ];
137
+                    }
138
+                }
139
+            }
140
+        }
141 141
 
142
-		if (!$this->shareeEnumeration) {
143
-			$result['wide'] = [];
144
-		} else {
145
-			$result['wide'] = array_slice($result['wide'], $offset, $limit);
146
-		}
142
+        if (!$this->shareeEnumeration) {
143
+            $result['wide'] = [];
144
+        } else {
145
+            $result['wide'] = array_slice($result['wide'], $offset, $limit);
146
+        }
147 147
 
148
-		/**
149
-		 * Add generic share with remote item for valid cloud ids that are not users of the local instance
150
-		 */
151
-		if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
152
-			try {
153
-				list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
154
-				$localUser = $this->userManager->get($remoteUser);
155
-				if ($localUser === null || $search !== $localUser->getCloudId()) {
156
-					$result['exact'][] = [
157
-						'label' => $remoteUser . " ($serverUrl)",
158
-						'uuid' => $remoteUser,
159
-						'name' => $remoteUser,
160
-						'value' => [
161
-							'shareType' => Share::SHARE_TYPE_REMOTE,
162
-							'shareWith' => $search,
163
-							'server' => $serverUrl,
164
-						],
165
-					];
166
-				}
167
-			} catch (\InvalidArgumentException $e) {
168
-			}
169
-		}
148
+        /**
149
+         * Add generic share with remote item for valid cloud ids that are not users of the local instance
150
+         */
151
+        if (!$searchResult->hasExactIdMatch($resultType) && $this->cloudIdManager->isValidCloudId($search) && $offset === 0) {
152
+            try {
153
+                list($remoteUser, $serverUrl) = $this->splitUserRemote($search);
154
+                $localUser = $this->userManager->get($remoteUser);
155
+                if ($localUser === null || $search !== $localUser->getCloudId()) {
156
+                    $result['exact'][] = [
157
+                        'label' => $remoteUser . " ($serverUrl)",
158
+                        'uuid' => $remoteUser,
159
+                        'name' => $remoteUser,
160
+                        'value' => [
161
+                            'shareType' => Share::SHARE_TYPE_REMOTE,
162
+                            'shareWith' => $search,
163
+                            'server' => $serverUrl,
164
+                        ],
165
+                    ];
166
+                }
167
+            } catch (\InvalidArgumentException $e) {
168
+            }
169
+        }
170 170
 
171
-		$searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
171
+        $searchResult->addResultSet($resultType, $result['wide'], $result['exact']);
172 172
 
173
-		return true;
174
-	}
173
+        return true;
174
+    }
175 175
 
176
-	/**
177
-	 * split user and remote from federated cloud id
178
-	 *
179
-	 * @param string $address federated share address
180
-	 * @return array [user, remoteURL]
181
-	 * @throws \InvalidArgumentException
182
-	 */
183
-	public function splitUserRemote($address) {
184
-		try {
185
-			$cloudId = $this->cloudIdManager->resolveCloudId($address);
186
-			return [$cloudId->getUser(), $cloudId->getRemote()];
187
-		} catch (\InvalidArgumentException $e) {
188
-			throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
189
-		}
190
-	}
176
+    /**
177
+     * split user and remote from federated cloud id
178
+     *
179
+     * @param string $address federated share address
180
+     * @return array [user, remoteURL]
181
+     * @throws \InvalidArgumentException
182
+     */
183
+    public function splitUserRemote($address) {
184
+        try {
185
+            $cloudId = $this->cloudIdManager->resolveCloudId($address);
186
+            return [$cloudId->getUser(), $cloudId->getRemote()];
187
+        } catch (\InvalidArgumentException $e) {
188
+            throw new \InvalidArgumentException('Invalid Federated Cloud ID', 0, $e);
189
+        }
190
+    }
191 191
 }
Please login to merge, or discard this patch.
Spacing   +3 added lines, -3 removed lines patch added patch discarded remove patch
@@ -112,7 +112,7 @@  discard block
 block discarded – undo
112 112
 							$searchResult->markExactIdMatch($resultType);
113 113
 						}
114 114
 						$result['exact'][] = [
115
-							'label' => $contact['FN'] . " ($cloudId)",
115
+							'label' => $contact['FN']." ($cloudId)",
116 116
 							'uuid' => $contact['UID'],
117 117
 							'name' => $contact['FN'],
118 118
 							'type' => $cloudIdType,
@@ -124,7 +124,7 @@  discard block
 block discarded – undo
124 124
 						];
125 125
 					} else {
126 126
 						$result['wide'][] = [
127
-							'label' => $contact['FN'] . " ($cloudId)",
127
+							'label' => $contact['FN']." ($cloudId)",
128 128
 							'uuid' => $contact['UID'],
129 129
 							'name' => $contact['FN'],
130 130
 							'type' => $cloudIdType,
@@ -154,7 +154,7 @@  discard block
 block discarded – undo
154 154
 				$localUser = $this->userManager->get($remoteUser);
155 155
 				if ($localUser === null || $search !== $localUser->getCloudId()) {
156 156
 					$result['exact'][] = [
157
-						'label' => $remoteUser . " ($serverUrl)",
157
+						'label' => $remoteUser." ($serverUrl)",
158 158
 						'uuid' => $remoteUser,
159 159
 						'name' => $remoteUser,
160 160
 						'value' => [
Please login to merge, or discard this patch.
lib/private/ContactsManager.php 1 patch
Indentation   +177 added lines, -177 removed lines patch added patch discarded remove patch
@@ -30,181 +30,181 @@
 block discarded – undo
30 30
 
31 31
 namespace OC {
32 32
 
33
-	class ContactsManager implements \OCP\Contacts\IManager {
34
-
35
-		/**
36
-		 * This function is used to search and find contacts within the users address books.
37
-		 * In case $pattern is empty all contacts will be returned.
38
-		 *
39
-		 * @param string $pattern which should match within the $searchProperties
40
-		 * @param array $searchProperties defines the properties within the query pattern should match
41
-		 * @param array $options = array() to define the search behavior
42
-		 * 	- 'escape_like_param' - If set to false wildcards _ and % are not escaped
43
-		 * @return array an array of contacts which are arrays of key-value-pairs
44
-		 */
45
-		public function search($pattern, $searchProperties = [], $options = []) {
46
-			$this->loadAddressBooks();
47
-			$result = [];
48
-			foreach($this->addressBooks as $addressBook) {
49
-				$r = $addressBook->search($pattern, $searchProperties, $options);
50
-				$contacts = [];
51
-				foreach($r as $c){
52
-					$c['addressbook-key'] = $addressBook->getKey();
53
-					$contacts[] = $c;
54
-				}
55
-				$result = array_merge($result, $contacts);
56
-			}
57
-
58
-			return $result;
59
-		}
60
-
61
-		/**
62
-		 * This function can be used to delete the contact identified by the given id
63
-		 *
64
-		 * @param object $id the unique identifier to a contact
65
-		 * @param string $addressBookKey identifier of the address book in which the contact shall be deleted
66
-		 * @return bool successful or not
67
-		 */
68
-		public function delete($id, $addressBookKey) {
69
-			$addressBook = $this->getAddressBook($addressBookKey);
70
-			if (!$addressBook) {
71
-				return null;
72
-			}
73
-
74
-			if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
75
-				return $addressBook->delete($id);
76
-			}
77
-
78
-			return null;
79
-		}
80
-
81
-		/**
82
-		 * This function is used to create a new contact if 'id' is not given or not present.
83
-		 * Otherwise the contact will be updated by replacing the entire data set.
84
-		 *
85
-		 * @param array $properties this array if key-value-pairs defines a contact
86
-		 * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated
87
-		 * @return array representing the contact just created or updated
88
-		 */
89
-		public function createOrUpdate($properties, $addressBookKey) {
90
-			$addressBook = $this->getAddressBook($addressBookKey);
91
-			if (!$addressBook) {
92
-				return null;
93
-			}
94
-
95
-			if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
96
-				return $addressBook->createOrUpdate($properties);
97
-			}
98
-
99
-			return null;
100
-		}
101
-
102
-		/**
103
-		 * Check if contacts are available (e.g. contacts app enabled)
104
-		 *
105
-		 * @return bool true if enabled, false if not
106
-		 */
107
-		public function isEnabled() {
108
-			return !empty($this->addressBooks) || !empty($this->addressBookLoaders);
109
-		}
110
-
111
-		/**
112
-		 * @param \OCP\IAddressBook $addressBook
113
-		 */
114
-		public function registerAddressBook(\OCP\IAddressBook $addressBook) {
115
-			$this->addressBooks[$addressBook->getKey()] = $addressBook;
116
-		}
117
-
118
-		/**
119
-		 * @param \OCP\IAddressBook $addressBook
120
-		 */
121
-		public function unregisterAddressBook(\OCP\IAddressBook $addressBook) {
122
-			unset($this->addressBooks[$addressBook->getKey()]);
123
-		}
124
-
125
-		/**
126
-		 * Return a list of the user's addressbooks display names
127
-		 * ! The addressBook displayName are not unique, please use getUserAddressBooks
128
-		 *
129
-		 * @return array
130
-		 * @since 6.0.0
131
-		 * @deprecated 16.0.0 - Use `$this->getUserAddressBooks()` instead
132
-		 */
133
-		public function getAddressBooks() {
134
-			$this->loadAddressBooks();
135
-			$result = [];
136
-			foreach($this->addressBooks as $addressBook) {
137
-				$result[$addressBook->getKey()] = $addressBook->getDisplayName();
138
-			}
139
-
140
-			return $result;
141
-		}
142
-
143
-		/**
144
-		 * Return a list of the user's addressbooks
145
-		 *
146
-		 * @return IAddressBook[]
147
-		 * @since 16.0.0
148
-		 */
149
-		public function getUserAddressBooks(): array {
150
-			$this->loadAddressBooks();
151
-			return $this->addressBooks;
152
-		}
153
-
154
-		/**
155
-		 * removes all registered address book instances
156
-		 */
157
-		public function clear() {
158
-			$this->addressBooks = [];
159
-			$this->addressBookLoaders = [];
160
-		}
161
-
162
-		/**
163
-		 * @var \OCP\IAddressBook[] which holds all registered address books
164
-		 */
165
-		private $addressBooks = [];
166
-
167
-		/**
168
-		 * @var \Closure[] to call to load/register address books
169
-		 */
170
-		private $addressBookLoaders = [];
171
-
172
-		/**
173
-		 * In order to improve lazy loading a closure can be registered which will be called in case
174
-		 * address books are actually requested
175
-		 *
176
-		 * @param \Closure $callable
177
-		 */
178
-		public function register(\Closure $callable)
179
-		{
180
-			$this->addressBookLoaders[] = $callable;
181
-		}
182
-
183
-		/**
184
-		 * Get (and load when needed) the address book for $key
185
-		 *
186
-		 * @param string $addressBookKey
187
-		 * @return \OCP\IAddressBook
188
-		 */
189
-		protected function getAddressBook($addressBookKey)
190
-		{
191
-			$this->loadAddressBooks();
192
-			if (!array_key_exists($addressBookKey, $this->addressBooks)) {
193
-				return null;
194
-			}
195
-
196
-			return $this->addressBooks[$addressBookKey];
197
-		}
198
-
199
-		/**
200
-		 * Load all address books registered with 'register'
201
-		 */
202
-		protected function loadAddressBooks()
203
-		{
204
-			foreach($this->addressBookLoaders as $callable) {
205
-				$callable($this);
206
-			}
207
-			$this->addressBookLoaders = [];
208
-		}
209
-	}
33
+    class ContactsManager implements \OCP\Contacts\IManager {
34
+
35
+        /**
36
+         * This function is used to search and find contacts within the users address books.
37
+         * In case $pattern is empty all contacts will be returned.
38
+         *
39
+         * @param string $pattern which should match within the $searchProperties
40
+         * @param array $searchProperties defines the properties within the query pattern should match
41
+         * @param array $options = array() to define the search behavior
42
+         * 	- 'escape_like_param' - If set to false wildcards _ and % are not escaped
43
+         * @return array an array of contacts which are arrays of key-value-pairs
44
+         */
45
+        public function search($pattern, $searchProperties = [], $options = []) {
46
+            $this->loadAddressBooks();
47
+            $result = [];
48
+            foreach($this->addressBooks as $addressBook) {
49
+                $r = $addressBook->search($pattern, $searchProperties, $options);
50
+                $contacts = [];
51
+                foreach($r as $c){
52
+                    $c['addressbook-key'] = $addressBook->getKey();
53
+                    $contacts[] = $c;
54
+                }
55
+                $result = array_merge($result, $contacts);
56
+            }
57
+
58
+            return $result;
59
+        }
60
+
61
+        /**
62
+         * This function can be used to delete the contact identified by the given id
63
+         *
64
+         * @param object $id the unique identifier to a contact
65
+         * @param string $addressBookKey identifier of the address book in which the contact shall be deleted
66
+         * @return bool successful or not
67
+         */
68
+        public function delete($id, $addressBookKey) {
69
+            $addressBook = $this->getAddressBook($addressBookKey);
70
+            if (!$addressBook) {
71
+                return null;
72
+            }
73
+
74
+            if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_DELETE) {
75
+                return $addressBook->delete($id);
76
+            }
77
+
78
+            return null;
79
+        }
80
+
81
+        /**
82
+         * This function is used to create a new contact if 'id' is not given or not present.
83
+         * Otherwise the contact will be updated by replacing the entire data set.
84
+         *
85
+         * @param array $properties this array if key-value-pairs defines a contact
86
+         * @param string $addressBookKey identifier of the address book in which the contact shall be created or updated
87
+         * @return array representing the contact just created or updated
88
+         */
89
+        public function createOrUpdate($properties, $addressBookKey) {
90
+            $addressBook = $this->getAddressBook($addressBookKey);
91
+            if (!$addressBook) {
92
+                return null;
93
+            }
94
+
95
+            if ($addressBook->getPermissions() & \OCP\Constants::PERMISSION_CREATE) {
96
+                return $addressBook->createOrUpdate($properties);
97
+            }
98
+
99
+            return null;
100
+        }
101
+
102
+        /**
103
+         * Check if contacts are available (e.g. contacts app enabled)
104
+         *
105
+         * @return bool true if enabled, false if not
106
+         */
107
+        public function isEnabled() {
108
+            return !empty($this->addressBooks) || !empty($this->addressBookLoaders);
109
+        }
110
+
111
+        /**
112
+         * @param \OCP\IAddressBook $addressBook
113
+         */
114
+        public function registerAddressBook(\OCP\IAddressBook $addressBook) {
115
+            $this->addressBooks[$addressBook->getKey()] = $addressBook;
116
+        }
117
+
118
+        /**
119
+         * @param \OCP\IAddressBook $addressBook
120
+         */
121
+        public function unregisterAddressBook(\OCP\IAddressBook $addressBook) {
122
+            unset($this->addressBooks[$addressBook->getKey()]);
123
+        }
124
+
125
+        /**
126
+         * Return a list of the user's addressbooks display names
127
+         * ! The addressBook displayName are not unique, please use getUserAddressBooks
128
+         *
129
+         * @return array
130
+         * @since 6.0.0
131
+         * @deprecated 16.0.0 - Use `$this->getUserAddressBooks()` instead
132
+         */
133
+        public function getAddressBooks() {
134
+            $this->loadAddressBooks();
135
+            $result = [];
136
+            foreach($this->addressBooks as $addressBook) {
137
+                $result[$addressBook->getKey()] = $addressBook->getDisplayName();
138
+            }
139
+
140
+            return $result;
141
+        }
142
+
143
+        /**
144
+         * Return a list of the user's addressbooks
145
+         *
146
+         * @return IAddressBook[]
147
+         * @since 16.0.0
148
+         */
149
+        public function getUserAddressBooks(): array {
150
+            $this->loadAddressBooks();
151
+            return $this->addressBooks;
152
+        }
153
+
154
+        /**
155
+         * removes all registered address book instances
156
+         */
157
+        public function clear() {
158
+            $this->addressBooks = [];
159
+            $this->addressBookLoaders = [];
160
+        }
161
+
162
+        /**
163
+         * @var \OCP\IAddressBook[] which holds all registered address books
164
+         */
165
+        private $addressBooks = [];
166
+
167
+        /**
168
+         * @var \Closure[] to call to load/register address books
169
+         */
170
+        private $addressBookLoaders = [];
171
+
172
+        /**
173
+         * In order to improve lazy loading a closure can be registered which will be called in case
174
+         * address books are actually requested
175
+         *
176
+         * @param \Closure $callable
177
+         */
178
+        public function register(\Closure $callable)
179
+        {
180
+            $this->addressBookLoaders[] = $callable;
181
+        }
182
+
183
+        /**
184
+         * Get (and load when needed) the address book for $key
185
+         *
186
+         * @param string $addressBookKey
187
+         * @return \OCP\IAddressBook
188
+         */
189
+        protected function getAddressBook($addressBookKey)
190
+        {
191
+            $this->loadAddressBooks();
192
+            if (!array_key_exists($addressBookKey, $this->addressBooks)) {
193
+                return null;
194
+            }
195
+
196
+            return $this->addressBooks[$addressBookKey];
197
+        }
198
+
199
+        /**
200
+         * Load all address books registered with 'register'
201
+         */
202
+        protected function loadAddressBooks()
203
+        {
204
+            foreach($this->addressBookLoaders as $callable) {
205
+                $callable($this);
206
+            }
207
+            $this->addressBookLoaders = [];
208
+        }
209
+    }
210 210
 }
Please login to merge, or discard this patch.
lib/private/Color.php 1 patch
Indentation   +8 added lines, -8 removed lines patch added patch discarded remove patch
@@ -24,12 +24,12 @@
 block discarded – undo
24 24
 namespace OC;
25 25
 
26 26
 class Color {
27
-	public $r;
28
-	public $g;
29
-	public $b;
30
-	public function __construct($r, $g, $b) {
31
-		$this->r = $r;
32
-		$this->g = $g;
33
-		$this->b = $b;
34
-	}
27
+    public $r;
28
+    public $g;
29
+    public $b;
30
+    public function __construct($r, $g, $b) {
31
+        $this->r = $r;
32
+        $this->g = $g;
33
+        $this->b = $b;
34
+    }
35 35
 }
Please login to merge, or discard this patch.
lib/private/TemplateLayout.php 3 patches
Indentation   +309 added lines, -309 removed lines patch added patch discarded remove patch
@@ -53,313 +53,313 @@
 block discarded – undo
53 53
 
54 54
 class TemplateLayout extends \OC_Template {
55 55
 
56
-	private static $versionHash = '';
57
-
58
-	/**
59
-	 * @var \OCP\IConfig
60
-	 */
61
-	private $config;
62
-
63
-	/**
64
-	 * @param string $renderAs
65
-	 * @param string $appId application id
66
-	 */
67
-	public function __construct($renderAs, $appId = '') {
68
-
69
-		// yes - should be injected ....
70
-		$this->config = \OC::$server->getConfig();
71
-
72
-		if(\OCP\Util::isIE()) {
73
-			\OC_Util::addStyle('ie');
74
-		}
75
-
76
-		// Decide which page we show
77
-		if($renderAs === 'user') {
78
-			parent::__construct('core', 'layout.user');
79
-			if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
80
-				$this->assign('bodyid', 'body-settings');
81
-			}else{
82
-				$this->assign('bodyid', 'body-user');
83
-			}
84
-
85
-			// Add navigation entry
86
-			$this->assign('application', '');
87
-			$this->assign('appid', $appId);
88
-			$navigation = \OC::$server->getNavigationManager()->getAll();
89
-			$this->assign('navigation', $navigation);
90
-			$settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
91
-			$this->assign('settingsnavigation', $settingsNavigation);
92
-			foreach($navigation as $entry) {
93
-				if ($entry['active']) {
94
-					$this->assign('application', $entry['name']);
95
-					break;
96
-				}
97
-			}
98
-
99
-			foreach($settingsNavigation as $entry) {
100
-				if ($entry['active']) {
101
-					$this->assign('application', $entry['name']);
102
-					break;
103
-				}
104
-			}
105
-			$userDisplayName = \OC_User::getDisplayName();
106
-			$this->assign('user_displayname', $userDisplayName);
107
-			$this->assign('user_uid', \OC_User::getUser());
108
-
109
-			if (\OC_User::getUser() === false) {
110
-				$this->assign('userAvatarSet', false);
111
-			} else {
112
-				$this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
113
-				$this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
114
-			}
115
-
116
-			// check if app menu icons should be inverted
117
-			try {
118
-				/** @var \OCA\Theming\Util $util */
119
-				$util = \OC::$server->query(\OCA\Theming\Util::class);
120
-				$this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
121
-			} catch (\OCP\AppFramework\QueryException $e) {
122
-				$this->assign('themingInvertMenu', false);
123
-			} catch (\OCP\AutoloadNotAllowedException $e) {
124
-				$this->assign('themingInvertMenu', false);
125
-			}
126
-
127
-		} else if ($renderAs === 'error') {
128
-			parent::__construct('core', 'layout.guest', '', false);
129
-			$this->assign('bodyid', 'body-login');
130
-			$this->assign('user_displayname', '');
131
-			$this->assign('user_uid', '');
132
-		} else if ($renderAs === 'guest') {
133
-			parent::__construct('core', 'layout.guest');
134
-			\OC_Util::addStyle('guest');
135
-			$this->assign('bodyid', 'body-login');
136
-
137
-			$userDisplayName = \OC_User::getDisplayName();
138
-			$this->assign('user_displayname', $userDisplayName);
139
-			$this->assign('user_uid', \OC_User::getUser());
140
-		} else if ($renderAs === 'public') {
141
-			parent::__construct('core', 'layout.public');
142
-			$this->assign('appid', $appId);
143
-			$this->assign('bodyid', 'body-public');
144
-
145
-			/** @var IRegistry $subscription */
146
-			$subscription = \OC::$server->query(IRegistry::class);
147
-			$showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true);
148
-			if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) {
149
-				$showSimpleSignup = false;
150
-			}
151
-			$this->assign('showSimpleSignUpLink', $showSimpleSignup);
152
-		} else {
153
-			parent::__construct('core', 'layout.base');
154
-
155
-		}
156
-		// Send the language and the locale to our layouts
157
-		$lang = \OC::$server->getL10NFactory()->findLanguage();
158
-		$locale = \OC::$server->getL10NFactory()->findLocale($lang);
159
-
160
-		$lang = str_replace('_', '-', $lang);
161
-		$this->assign('language', $lang);
162
-		$this->assign('locale', $locale);
163
-
164
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
165
-			if (empty(self::$versionHash)) {
166
-				$v = \OC_App::getAppVersions();
167
-				$v['core'] = implode('.', \OCP\Util::getVersion());
168
-				self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
169
-			}
170
-		} else {
171
-			self::$versionHash = md5('not installed');
172
-		}
173
-
174
-		// Add the js files
175
-		$jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
176
-		$this->assign('jsfiles', []);
177
-		if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
178
-			if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
179
-				$jsConfigHelper = new JSConfigHelper(
180
-					\OC::$server->getL10N('lib'),
181
-					\OC::$server->query(Defaults::class),
182
-					\OC::$server->getAppManager(),
183
-					\OC::$server->getSession(),
184
-					\OC::$server->getUserSession()->getUser(),
185
-					$this->config,
186
-					\OC::$server->getGroupManager(),
187
-					\OC::$server->getIniWrapper(),
188
-					\OC::$server->getURLGenerator(),
189
-					\OC::$server->getCapabilitiesManager()
190
-				);
191
-				$this->assign('inline_ocjs', $jsConfigHelper->getConfig());
192
-			} else {
193
-				$this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
194
-			}
195
-		}
196
-		foreach($jsFiles as $info) {
197
-			$web = $info[1];
198
-			$file = $info[2];
199
-			$this->append('jsfiles', $web.'/'.$file . $this->getVersionHashSuffix());
200
-		}
201
-
202
-		try {
203
-			$pathInfo = \OC::$server->getRequest()->getPathInfo();
204
-		} catch (\Exception $e) {
205
-			$pathInfo = '';
206
-		}
207
-
208
-		// Do not initialise scss appdata until we have a fully installed instance
209
-		// Do not load scss for update, errors, installation or login page
210
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)
211
-			&& !\OCP\Util::needUpgrade()
212
-			&& $pathInfo !== ''
213
-			&& !preg_match('/^\/login/', $pathInfo)
214
-			&& $renderAs !== 'error'
215
-		) {
216
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
217
-		} else {
218
-			// If we ignore the scss compiler,
219
-			// we need to load the guest css fallback
220
-			\OC_Util::addStyle('guest');
221
-			$cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
222
-		}
223
-
224
-		$this->assign('cssfiles', []);
225
-		$this->assign('printcssfiles', []);
226
-		$this->assign('versionHash', self::$versionHash);
227
-		foreach($cssFiles as $info) {
228
-			$web = $info[1];
229
-			$file = $info[2];
230
-
231
-			if (substr($file, -strlen('print.css')) === 'print.css') {
232
-				$this->append('printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix());
233
-			} else {
234
-				$suffix = $this->getVersionHashSuffix($web, $file);
235
-
236
-				if (strpos($file, '?v=') == false) {
237
-					$this->append('cssfiles', $web.'/'.$file . $suffix);
238
-				} else {
239
-					$this->append('cssfiles', $web.'/'.$file . '-' . substr($suffix, 3));
240
-				}
241
-
242
-			}
243
-		}
244
-
245
-		/** @var InitialStateService $initialState */
246
-		$initialState = \OC::$server->query(InitialStateService::class);
247
-		$this->assign('initialStates', $initialState->getInitialStates());
248
-	}
249
-
250
-	/**
251
-	 * @param string $path
252
-	 * @param string $file
253
-	 * @return string
254
-	 */
255
-	protected function getVersionHashSuffix($path = false, $file = false) {
256
-		if ($this->config->getSystemValue('debug', false)) {
257
-			// allows chrome workspace mapping in debug mode
258
-			return "";
259
-		}
260
-		$themingSuffix = '';
261
-		$v = [];
262
-
263
-		if ($this->config->getSystemValue('installed', false)) {
264
-			if (\OC::$server->getAppManager()->isInstalled('theming')) {
265
-				$themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
266
-			}
267
-			$v = \OC_App::getAppVersions();
268
-		}
269
-
270
-		// Try the webroot path for a match
271
-		if ($path !== false && $path !== '') {
272
-			$appName = $this->getAppNamefromPath($path);
273
-			if(array_key_exists($appName, $v)) {
274
-				$appVersion = $v[$appName];
275
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
276
-			}
277
-		}
278
-		// fallback to the file path instead
279
-		if ($file !== false && $file !== '') {
280
-			$appName = $this->getAppNamefromPath($file);
281
-			if(array_key_exists($appName, $v)) {
282
-				$appVersion = $v[$appName];
283
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
284
-			}
285
-		}
286
-
287
-		return '?v=' . self::$versionHash . $themingSuffix;
288
-	}
289
-
290
-	/**
291
-	 * @param array $styles
292
-	 * @return array
293
-	 */
294
-	static public function findStylesheetFiles($styles, $compileScss = true) {
295
-		// Read the selected theme from the config file
296
-		$theme = \OC_Util::getTheme();
297
-
298
-		if($compileScss) {
299
-			$SCSSCacher = \OC::$server->query(SCSSCacher::class);
300
-		} else {
301
-			$SCSSCacher = null;
302
-		}
303
-
304
-		$locator = new \OC\Template\CSSResourceLocator(
305
-			\OC::$server->getLogger(),
306
-			$theme,
307
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
308
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
309
-			$SCSSCacher
310
-		);
311
-		$locator->find($styles);
312
-		return $locator->getResources();
313
-	}
314
-
315
-	/**
316
-	 * @param string $path
317
-	 * @return string|boolean
318
-	 */
319
-	public function getAppNamefromPath($path) {
320
-		if ($path !== '' && is_string($path)) {
321
-			$pathParts = explode('/', $path);
322
-			if ($pathParts[0] === 'css') {
323
-				// This is a scss request
324
-				return $pathParts[1];
325
-			}
326
-			return end($pathParts);
327
-		}
328
-		return false;
329
-
330
-	}
331
-
332
-	/**
333
-	 * @param array $scripts
334
-	 * @return array
335
-	 */
336
-	static public function findJavascriptFiles($scripts) {
337
-		// Read the selected theme from the config file
338
-		$theme = \OC_Util::getTheme();
339
-
340
-		$locator = new \OC\Template\JSResourceLocator(
341
-			\OC::$server->getLogger(),
342
-			$theme,
343
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
344
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
345
-			\OC::$server->query(JSCombiner::class)
346
-			);
347
-		$locator->find($scripts);
348
-		return $locator->getResources();
349
-	}
350
-
351
-	/**
352
-	 * Converts the absolute file path to a relative path from \OC::$SERVERROOT
353
-	 * @param string $filePath Absolute path
354
-	 * @return string Relative path
355
-	 * @throws \Exception If $filePath is not under \OC::$SERVERROOT
356
-	 */
357
-	public static function convertToRelativePath($filePath) {
358
-		$relativePath = explode(\OC::$SERVERROOT, $filePath);
359
-		if(count($relativePath) !== 2) {
360
-			throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
361
-		}
362
-
363
-		return $relativePath[1];
364
-	}
56
+    private static $versionHash = '';
57
+
58
+    /**
59
+     * @var \OCP\IConfig
60
+     */
61
+    private $config;
62
+
63
+    /**
64
+     * @param string $renderAs
65
+     * @param string $appId application id
66
+     */
67
+    public function __construct($renderAs, $appId = '') {
68
+
69
+        // yes - should be injected ....
70
+        $this->config = \OC::$server->getConfig();
71
+
72
+        if(\OCP\Util::isIE()) {
73
+            \OC_Util::addStyle('ie');
74
+        }
75
+
76
+        // Decide which page we show
77
+        if($renderAs === 'user') {
78
+            parent::__construct('core', 'layout.user');
79
+            if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
80
+                $this->assign('bodyid', 'body-settings');
81
+            }else{
82
+                $this->assign('bodyid', 'body-user');
83
+            }
84
+
85
+            // Add navigation entry
86
+            $this->assign('application', '');
87
+            $this->assign('appid', $appId);
88
+            $navigation = \OC::$server->getNavigationManager()->getAll();
89
+            $this->assign('navigation', $navigation);
90
+            $settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
91
+            $this->assign('settingsnavigation', $settingsNavigation);
92
+            foreach($navigation as $entry) {
93
+                if ($entry['active']) {
94
+                    $this->assign('application', $entry['name']);
95
+                    break;
96
+                }
97
+            }
98
+
99
+            foreach($settingsNavigation as $entry) {
100
+                if ($entry['active']) {
101
+                    $this->assign('application', $entry['name']);
102
+                    break;
103
+                }
104
+            }
105
+            $userDisplayName = \OC_User::getDisplayName();
106
+            $this->assign('user_displayname', $userDisplayName);
107
+            $this->assign('user_uid', \OC_User::getUser());
108
+
109
+            if (\OC_User::getUser() === false) {
110
+                $this->assign('userAvatarSet', false);
111
+            } else {
112
+                $this->assign('userAvatarSet', \OC::$server->getAvatarManager()->getAvatar(\OC_User::getUser())->exists());
113
+                $this->assign('userAvatarVersion', $this->config->getUserValue(\OC_User::getUser(), 'avatar', 'version', 0));
114
+            }
115
+
116
+            // check if app menu icons should be inverted
117
+            try {
118
+                /** @var \OCA\Theming\Util $util */
119
+                $util = \OC::$server->query(\OCA\Theming\Util::class);
120
+                $this->assign('themingInvertMenu', $util->invertTextColor(\OC::$server->getThemingDefaults()->getColorPrimary()));
121
+            } catch (\OCP\AppFramework\QueryException $e) {
122
+                $this->assign('themingInvertMenu', false);
123
+            } catch (\OCP\AutoloadNotAllowedException $e) {
124
+                $this->assign('themingInvertMenu', false);
125
+            }
126
+
127
+        } else if ($renderAs === 'error') {
128
+            parent::__construct('core', 'layout.guest', '', false);
129
+            $this->assign('bodyid', 'body-login');
130
+            $this->assign('user_displayname', '');
131
+            $this->assign('user_uid', '');
132
+        } else if ($renderAs === 'guest') {
133
+            parent::__construct('core', 'layout.guest');
134
+            \OC_Util::addStyle('guest');
135
+            $this->assign('bodyid', 'body-login');
136
+
137
+            $userDisplayName = \OC_User::getDisplayName();
138
+            $this->assign('user_displayname', $userDisplayName);
139
+            $this->assign('user_uid', \OC_User::getUser());
140
+        } else if ($renderAs === 'public') {
141
+            parent::__construct('core', 'layout.public');
142
+            $this->assign('appid', $appId);
143
+            $this->assign('bodyid', 'body-public');
144
+
145
+            /** @var IRegistry $subscription */
146
+            $subscription = \OC::$server->query(IRegistry::class);
147
+            $showSimpleSignup = $this->config->getSystemValueBool('simpleSignUpLink.shown', true);
148
+            if ($showSimpleSignup && $subscription->delegateHasValidSubscription()) {
149
+                $showSimpleSignup = false;
150
+            }
151
+            $this->assign('showSimpleSignUpLink', $showSimpleSignup);
152
+        } else {
153
+            parent::__construct('core', 'layout.base');
154
+
155
+        }
156
+        // Send the language and the locale to our layouts
157
+        $lang = \OC::$server->getL10NFactory()->findLanguage();
158
+        $locale = \OC::$server->getL10NFactory()->findLocale($lang);
159
+
160
+        $lang = str_replace('_', '-', $lang);
161
+        $this->assign('language', $lang);
162
+        $this->assign('locale', $locale);
163
+
164
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
165
+            if (empty(self::$versionHash)) {
166
+                $v = \OC_App::getAppVersions();
167
+                $v['core'] = implode('.', \OCP\Util::getVersion());
168
+                self::$versionHash = substr(md5(implode(',', $v)), 0, 8);
169
+            }
170
+        } else {
171
+            self::$versionHash = md5('not installed');
172
+        }
173
+
174
+        // Add the js files
175
+        $jsFiles = self::findJavascriptFiles(\OC_Util::$scripts);
176
+        $this->assign('jsfiles', []);
177
+        if ($this->config->getSystemValue('installed', false) && $renderAs != 'error') {
178
+            if (\OC::$server->getContentSecurityPolicyNonceManager()->browserSupportsCspV3()) {
179
+                $jsConfigHelper = new JSConfigHelper(
180
+                    \OC::$server->getL10N('lib'),
181
+                    \OC::$server->query(Defaults::class),
182
+                    \OC::$server->getAppManager(),
183
+                    \OC::$server->getSession(),
184
+                    \OC::$server->getUserSession()->getUser(),
185
+                    $this->config,
186
+                    \OC::$server->getGroupManager(),
187
+                    \OC::$server->getIniWrapper(),
188
+                    \OC::$server->getURLGenerator(),
189
+                    \OC::$server->getCapabilitiesManager()
190
+                );
191
+                $this->assign('inline_ocjs', $jsConfigHelper->getConfig());
192
+            } else {
193
+                $this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
194
+            }
195
+        }
196
+        foreach($jsFiles as $info) {
197
+            $web = $info[1];
198
+            $file = $info[2];
199
+            $this->append('jsfiles', $web.'/'.$file . $this->getVersionHashSuffix());
200
+        }
201
+
202
+        try {
203
+            $pathInfo = \OC::$server->getRequest()->getPathInfo();
204
+        } catch (\Exception $e) {
205
+            $pathInfo = '';
206
+        }
207
+
208
+        // Do not initialise scss appdata until we have a fully installed instance
209
+        // Do not load scss for update, errors, installation or login page
210
+        if(\OC::$server->getSystemConfig()->getValue('installed', false)
211
+            && !\OCP\Util::needUpgrade()
212
+            && $pathInfo !== ''
213
+            && !preg_match('/^\/login/', $pathInfo)
214
+            && $renderAs !== 'error'
215
+        ) {
216
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles);
217
+        } else {
218
+            // If we ignore the scss compiler,
219
+            // we need to load the guest css fallback
220
+            \OC_Util::addStyle('guest');
221
+            $cssFiles = self::findStylesheetFiles(\OC_Util::$styles, false);
222
+        }
223
+
224
+        $this->assign('cssfiles', []);
225
+        $this->assign('printcssfiles', []);
226
+        $this->assign('versionHash', self::$versionHash);
227
+        foreach($cssFiles as $info) {
228
+            $web = $info[1];
229
+            $file = $info[2];
230
+
231
+            if (substr($file, -strlen('print.css')) === 'print.css') {
232
+                $this->append('printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix());
233
+            } else {
234
+                $suffix = $this->getVersionHashSuffix($web, $file);
235
+
236
+                if (strpos($file, '?v=') == false) {
237
+                    $this->append('cssfiles', $web.'/'.$file . $suffix);
238
+                } else {
239
+                    $this->append('cssfiles', $web.'/'.$file . '-' . substr($suffix, 3));
240
+                }
241
+
242
+            }
243
+        }
244
+
245
+        /** @var InitialStateService $initialState */
246
+        $initialState = \OC::$server->query(InitialStateService::class);
247
+        $this->assign('initialStates', $initialState->getInitialStates());
248
+    }
249
+
250
+    /**
251
+     * @param string $path
252
+     * @param string $file
253
+     * @return string
254
+     */
255
+    protected function getVersionHashSuffix($path = false, $file = false) {
256
+        if ($this->config->getSystemValue('debug', false)) {
257
+            // allows chrome workspace mapping in debug mode
258
+            return "";
259
+        }
260
+        $themingSuffix = '';
261
+        $v = [];
262
+
263
+        if ($this->config->getSystemValue('installed', false)) {
264
+            if (\OC::$server->getAppManager()->isInstalled('theming')) {
265
+                $themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
266
+            }
267
+            $v = \OC_App::getAppVersions();
268
+        }
269
+
270
+        // Try the webroot path for a match
271
+        if ($path !== false && $path !== '') {
272
+            $appName = $this->getAppNamefromPath($path);
273
+            if(array_key_exists($appName, $v)) {
274
+                $appVersion = $v[$appName];
275
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
276
+            }
277
+        }
278
+        // fallback to the file path instead
279
+        if ($file !== false && $file !== '') {
280
+            $appName = $this->getAppNamefromPath($file);
281
+            if(array_key_exists($appName, $v)) {
282
+                $appVersion = $v[$appName];
283
+                return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
284
+            }
285
+        }
286
+
287
+        return '?v=' . self::$versionHash . $themingSuffix;
288
+    }
289
+
290
+    /**
291
+     * @param array $styles
292
+     * @return array
293
+     */
294
+    static public function findStylesheetFiles($styles, $compileScss = true) {
295
+        // Read the selected theme from the config file
296
+        $theme = \OC_Util::getTheme();
297
+
298
+        if($compileScss) {
299
+            $SCSSCacher = \OC::$server->query(SCSSCacher::class);
300
+        } else {
301
+            $SCSSCacher = null;
302
+        }
303
+
304
+        $locator = new \OC\Template\CSSResourceLocator(
305
+            \OC::$server->getLogger(),
306
+            $theme,
307
+            [ \OC::$SERVERROOT => \OC::$WEBROOT ],
308
+            [ \OC::$SERVERROOT => \OC::$WEBROOT ],
309
+            $SCSSCacher
310
+        );
311
+        $locator->find($styles);
312
+        return $locator->getResources();
313
+    }
314
+
315
+    /**
316
+     * @param string $path
317
+     * @return string|boolean
318
+     */
319
+    public function getAppNamefromPath($path) {
320
+        if ($path !== '' && is_string($path)) {
321
+            $pathParts = explode('/', $path);
322
+            if ($pathParts[0] === 'css') {
323
+                // This is a scss request
324
+                return $pathParts[1];
325
+            }
326
+            return end($pathParts);
327
+        }
328
+        return false;
329
+
330
+    }
331
+
332
+    /**
333
+     * @param array $scripts
334
+     * @return array
335
+     */
336
+    static public function findJavascriptFiles($scripts) {
337
+        // Read the selected theme from the config file
338
+        $theme = \OC_Util::getTheme();
339
+
340
+        $locator = new \OC\Template\JSResourceLocator(
341
+            \OC::$server->getLogger(),
342
+            $theme,
343
+            [ \OC::$SERVERROOT => \OC::$WEBROOT ],
344
+            [ \OC::$SERVERROOT => \OC::$WEBROOT ],
345
+            \OC::$server->query(JSCombiner::class)
346
+            );
347
+        $locator->find($scripts);
348
+        return $locator->getResources();
349
+    }
350
+
351
+    /**
352
+     * Converts the absolute file path to a relative path from \OC::$SERVERROOT
353
+     * @param string $filePath Absolute path
354
+     * @return string Relative path
355
+     * @throws \Exception If $filePath is not under \OC::$SERVERROOT
356
+     */
357
+    public static function convertToRelativePath($filePath) {
358
+        $relativePath = explode(\OC::$SERVERROOT, $filePath);
359
+        if(count($relativePath) !== 2) {
360
+            throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
361
+        }
362
+
363
+        return $relativePath[1];
364
+    }
365 365
 }
Please login to merge, or discard this patch.
Spacing   +26 added lines, -26 removed lines patch added patch discarded remove patch
@@ -69,16 +69,16 @@  discard block
 block discarded – undo
69 69
 		// yes - should be injected ....
70 70
 		$this->config = \OC::$server->getConfig();
71 71
 
72
-		if(\OCP\Util::isIE()) {
72
+		if (\OCP\Util::isIE()) {
73 73
 			\OC_Util::addStyle('ie');
74 74
 		}
75 75
 
76 76
 		// Decide which page we show
77
-		if($renderAs === 'user') {
77
+		if ($renderAs === 'user') {
78 78
 			parent::__construct('core', 'layout.user');
79
-			if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
79
+			if (in_array(\OC_App::getCurrentApp(), ['settings', 'admin', 'help']) !== false) {
80 80
 				$this->assign('bodyid', 'body-settings');
81
-			}else{
81
+			} else {
82 82
 				$this->assign('bodyid', 'body-user');
83 83
 			}
84 84
 
@@ -89,14 +89,14 @@  discard block
 block discarded – undo
89 89
 			$this->assign('navigation', $navigation);
90 90
 			$settingsNavigation = \OC::$server->getNavigationManager()->getAll('settings');
91 91
 			$this->assign('settingsnavigation', $settingsNavigation);
92
-			foreach($navigation as $entry) {
92
+			foreach ($navigation as $entry) {
93 93
 				if ($entry['active']) {
94 94
 					$this->assign('application', $entry['name']);
95 95
 					break;
96 96
 				}
97 97
 			}
98 98
 
99
-			foreach($settingsNavigation as $entry) {
99
+			foreach ($settingsNavigation as $entry) {
100 100
 				if ($entry['active']) {
101 101
 					$this->assign('application', $entry['name']);
102 102
 					break;
@@ -161,7 +161,7 @@  discard block
 block discarded – undo
161 161
 		$this->assign('language', $lang);
162 162
 		$this->assign('locale', $locale);
163 163
 
164
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)) {
164
+		if (\OC::$server->getSystemConfig()->getValue('installed', false)) {
165 165
 			if (empty(self::$versionHash)) {
166 166
 				$v = \OC_App::getAppVersions();
167 167
 				$v['core'] = implode('.', \OCP\Util::getVersion());
@@ -193,10 +193,10 @@  discard block
 block discarded – undo
193 193
 				$this->append('jsfiles', \OC::$server->getURLGenerator()->linkToRoute('core.OCJS.getConfig', ['v' => self::$versionHash]));
194 194
 			}
195 195
 		}
196
-		foreach($jsFiles as $info) {
196
+		foreach ($jsFiles as $info) {
197 197
 			$web = $info[1];
198 198
 			$file = $info[2];
199
-			$this->append('jsfiles', $web.'/'.$file . $this->getVersionHashSuffix());
199
+			$this->append('jsfiles', $web.'/'.$file.$this->getVersionHashSuffix());
200 200
 		}
201 201
 
202 202
 		try {
@@ -207,7 +207,7 @@  discard block
 block discarded – undo
207 207
 
208 208
 		// Do not initialise scss appdata until we have a fully installed instance
209 209
 		// Do not load scss for update, errors, installation or login page
210
-		if(\OC::$server->getSystemConfig()->getValue('installed', false)
210
+		if (\OC::$server->getSystemConfig()->getValue('installed', false)
211 211
 			&& !\OCP\Util::needUpgrade()
212 212
 			&& $pathInfo !== ''
213 213
 			&& !preg_match('/^\/login/', $pathInfo)
@@ -224,19 +224,19 @@  discard block
 block discarded – undo
224 224
 		$this->assign('cssfiles', []);
225 225
 		$this->assign('printcssfiles', []);
226 226
 		$this->assign('versionHash', self::$versionHash);
227
-		foreach($cssFiles as $info) {
227
+		foreach ($cssFiles as $info) {
228 228
 			$web = $info[1];
229 229
 			$file = $info[2];
230 230
 
231 231
 			if (substr($file, -strlen('print.css')) === 'print.css') {
232
-				$this->append('printcssfiles', $web.'/'.$file . $this->getVersionHashSuffix());
232
+				$this->append('printcssfiles', $web.'/'.$file.$this->getVersionHashSuffix());
233 233
 			} else {
234 234
 				$suffix = $this->getVersionHashSuffix($web, $file);
235 235
 
236 236
 				if (strpos($file, '?v=') == false) {
237
-					$this->append('cssfiles', $web.'/'.$file . $suffix);
237
+					$this->append('cssfiles', $web.'/'.$file.$suffix);
238 238
 				} else {
239
-					$this->append('cssfiles', $web.'/'.$file . '-' . substr($suffix, 3));
239
+					$this->append('cssfiles', $web.'/'.$file.'-'.substr($suffix, 3));
240 240
 				}
241 241
 
242 242
 			}
@@ -262,7 +262,7 @@  discard block
 block discarded – undo
262 262
 
263 263
 		if ($this->config->getSystemValue('installed', false)) {
264 264
 			if (\OC::$server->getAppManager()->isInstalled('theming')) {
265
-				$themingSuffix = '-' . $this->config->getAppValue('theming', 'cachebuster', '0');
265
+				$themingSuffix = '-'.$this->config->getAppValue('theming', 'cachebuster', '0');
266 266
 			}
267 267
 			$v = \OC_App::getAppVersions();
268 268
 		}
@@ -270,21 +270,21 @@  discard block
 block discarded – undo
270 270
 		// Try the webroot path for a match
271 271
 		if ($path !== false && $path !== '') {
272 272
 			$appName = $this->getAppNamefromPath($path);
273
-			if(array_key_exists($appName, $v)) {
273
+			if (array_key_exists($appName, $v)) {
274 274
 				$appVersion = $v[$appName];
275
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
275
+				return '?v='.substr(md5($appVersion), 0, 8).$themingSuffix;
276 276
 			}
277 277
 		}
278 278
 		// fallback to the file path instead
279 279
 		if ($file !== false && $file !== '') {
280 280
 			$appName = $this->getAppNamefromPath($file);
281
-			if(array_key_exists($appName, $v)) {
281
+			if (array_key_exists($appName, $v)) {
282 282
 				$appVersion = $v[$appName];
283
-				return '?v=' . substr(md5($appVersion), 0, 8) . $themingSuffix;
283
+				return '?v='.substr(md5($appVersion), 0, 8).$themingSuffix;
284 284
 			}
285 285
 		}
286 286
 
287
-		return '?v=' . self::$versionHash . $themingSuffix;
287
+		return '?v='.self::$versionHash.$themingSuffix;
288 288
 	}
289 289
 
290 290
 	/**
@@ -295,7 +295,7 @@  discard block
 block discarded – undo
295 295
 		// Read the selected theme from the config file
296 296
 		$theme = \OC_Util::getTheme();
297 297
 
298
-		if($compileScss) {
298
+		if ($compileScss) {
299 299
 			$SCSSCacher = \OC::$server->query(SCSSCacher::class);
300 300
 		} else {
301 301
 			$SCSSCacher = null;
@@ -304,8 +304,8 @@  discard block
 block discarded – undo
304 304
 		$locator = new \OC\Template\CSSResourceLocator(
305 305
 			\OC::$server->getLogger(),
306 306
 			$theme,
307
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
308
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
307
+			[\OC::$SERVERROOT => \OC::$WEBROOT],
308
+			[\OC::$SERVERROOT => \OC::$WEBROOT],
309 309
 			$SCSSCacher
310 310
 		);
311 311
 		$locator->find($styles);
@@ -340,8 +340,8 @@  discard block
 block discarded – undo
340 340
 		$locator = new \OC\Template\JSResourceLocator(
341 341
 			\OC::$server->getLogger(),
342 342
 			$theme,
343
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
344
-			[ \OC::$SERVERROOT => \OC::$WEBROOT ],
343
+			[\OC::$SERVERROOT => \OC::$WEBROOT],
344
+			[\OC::$SERVERROOT => \OC::$WEBROOT],
345 345
 			\OC::$server->query(JSCombiner::class)
346 346
 			);
347 347
 		$locator->find($scripts);
@@ -356,7 +356,7 @@  discard block
 block discarded – undo
356 356
 	 */
357 357
 	public static function convertToRelativePath($filePath) {
358 358
 		$relativePath = explode(\OC::$SERVERROOT, $filePath);
359
-		if(count($relativePath) !== 2) {
359
+		if (count($relativePath) !== 2) {
360 360
 			throw new \Exception('$filePath is not under the \OC::$SERVERROOT');
361 361
 		}
362 362
 
Please login to merge, or discard this patch.
Braces   +1 added lines, -1 removed lines patch added patch discarded remove patch
@@ -78,7 +78,7 @@
 block discarded – undo
78 78
 			parent::__construct('core', 'layout.user');
79 79
 			if(in_array(\OC_App::getCurrentApp(), ['settings','admin', 'help']) !== false) {
80 80
 				$this->assign('bodyid', 'body-settings');
81
-			}else{
81
+			} else{
82 82
 				$this->assign('bodyid', 'body-user');
83 83
 			}
84 84
 
Please login to merge, or discard this patch.
lib/private/DB/Connection.php 2 patches
Indentation   +406 added lines, -406 removed lines patch added patch discarded remove patch
@@ -47,410 +47,410 @@
 block discarded – undo
47 47
 use OCP\PreConditionNotMetException;
48 48
 
49 49
 class Connection extends ReconnectWrapper implements IDBConnection {
50
-	/**
51
-	 * @var string $tablePrefix
52
-	 */
53
-	protected $tablePrefix;
54
-
55
-	/**
56
-	 * @var \OC\DB\Adapter $adapter
57
-	 */
58
-	protected $adapter;
59
-
60
-	protected $lockedTable = null;
61
-
62
-	public function connect() {
63
-		try {
64
-			return parent::connect();
65
-		} catch (DBALException $e) {
66
-			// throw a new exception to prevent leaking info from the stacktrace
67
-			throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
68
-		}
69
-	}
70
-
71
-	/**
72
-	 * Returns a QueryBuilder for the connection.
73
-	 *
74
-	 * @return \OCP\DB\QueryBuilder\IQueryBuilder
75
-	 */
76
-	public function getQueryBuilder() {
77
-		return new QueryBuilder(
78
-			$this,
79
-			\OC::$server->getSystemConfig(),
80
-			\OC::$server->getLogger()
81
-		);
82
-	}
83
-
84
-	/**
85
-	 * Gets the QueryBuilder for the connection.
86
-	 *
87
-	 * @return \Doctrine\DBAL\Query\QueryBuilder
88
-	 * @deprecated please use $this->getQueryBuilder() instead
89
-	 */
90
-	public function createQueryBuilder() {
91
-		$backtrace = $this->getCallerBacktrace();
92
-		\OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
93
-		return parent::createQueryBuilder();
94
-	}
95
-
96
-	/**
97
-	 * Gets the ExpressionBuilder for the connection.
98
-	 *
99
-	 * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
100
-	 * @deprecated please use $this->getQueryBuilder()->expr() instead
101
-	 */
102
-	public function getExpressionBuilder() {
103
-		$backtrace = $this->getCallerBacktrace();
104
-		\OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
105
-		return parent::getExpressionBuilder();
106
-	}
107
-
108
-	/**
109
-	 * Get the file and line that called the method where `getCallerBacktrace()` was used
110
-	 *
111
-	 * @return string
112
-	 */
113
-	protected function getCallerBacktrace() {
114
-		$traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
115
-
116
-		// 0 is the method where we use `getCallerBacktrace`
117
-		// 1 is the target method which uses the method we want to log
118
-		if (isset($traces[1])) {
119
-			return $traces[1]['file'] . ':' . $traces[1]['line'];
120
-		}
121
-
122
-		return '';
123
-	}
124
-
125
-	/**
126
-	 * @return string
127
-	 */
128
-	public function getPrefix() {
129
-		return $this->tablePrefix;
130
-	}
131
-
132
-	/**
133
-	 * Initializes a new instance of the Connection class.
134
-	 *
135
-	 * @param array $params  The connection parameters.
136
-	 * @param \Doctrine\DBAL\Driver $driver
137
-	 * @param \Doctrine\DBAL\Configuration $config
138
-	 * @param \Doctrine\Common\EventManager $eventManager
139
-	 * @throws \Exception
140
-	 */
141
-	public function __construct(array $params, Driver $driver, Configuration $config = null,
142
-		EventManager $eventManager = null)
143
-	{
144
-		if (!isset($params['adapter'])) {
145
-			throw new \Exception('adapter not set');
146
-		}
147
-		if (!isset($params['tablePrefix'])) {
148
-			throw new \Exception('tablePrefix not set');
149
-		}
150
-		parent::__construct($params, $driver, $config, $eventManager);
151
-		$this->adapter = new $params['adapter']($this);
152
-		$this->tablePrefix = $params['tablePrefix'];
153
-	}
154
-
155
-	/**
156
-	 * Prepares an SQL statement.
157
-	 *
158
-	 * @param string $statement The SQL statement to prepare.
159
-	 * @param int $limit
160
-	 * @param int $offset
161
-	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162
-	 */
163
-	public function prepare($statement, $limit=null, $offset=null) {
164
-		if ($limit === -1) {
165
-			$limit = null;
166
-		}
167
-		if (!is_null($limit)) {
168
-			$platform = $this->getDatabasePlatform();
169
-			$statement = $platform->modifyLimitQuery($statement, $limit, $offset);
170
-		}
171
-		$statement = $this->replaceTablePrefix($statement);
172
-		$statement = $this->adapter->fixupStatement($statement);
173
-
174
-		return parent::prepare($statement);
175
-	}
176
-
177
-	/**
178
-	 * Executes an, optionally parametrized, SQL query.
179
-	 *
180
-	 * If the query is parametrized, a prepared statement is used.
181
-	 * If an SQLLogger is configured, the execution is logged.
182
-	 *
183
-	 * @param string                                      $query  The SQL query to execute.
184
-	 * @param array                                       $params The parameters to bind to the query, if any.
185
-	 * @param array                                       $types  The types the previous parameters are in.
186
-	 * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
187
-	 *
188
-	 * @return \Doctrine\DBAL\Driver\Statement The executed statement.
189
-	 *
190
-	 * @throws \Doctrine\DBAL\DBALException
191
-	 */
192
-	public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
193
-	{
194
-		$query = $this->replaceTablePrefix($query);
195
-		$query = $this->adapter->fixupStatement($query);
196
-		return parent::executeQuery($query, $params, $types, $qcp);
197
-	}
198
-
199
-	/**
200
-	 * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
201
-	 * and returns the number of affected rows.
202
-	 *
203
-	 * This method supports PDO binding types as well as DBAL mapping types.
204
-	 *
205
-	 * @param string $query  The SQL query.
206
-	 * @param array  $params The query parameters.
207
-	 * @param array  $types  The parameter types.
208
-	 *
209
-	 * @return integer The number of affected rows.
210
-	 *
211
-	 * @throws \Doctrine\DBAL\DBALException
212
-	 */
213
-	public function executeUpdate($query, array $params = [], array $types = [])
214
-	{
215
-		$query = $this->replaceTablePrefix($query);
216
-		$query = $this->adapter->fixupStatement($query);
217
-		return parent::executeUpdate($query, $params, $types);
218
-	}
219
-
220
-	/**
221
-	 * Returns the ID of the last inserted row, or the last value from a sequence object,
222
-	 * depending on the underlying driver.
223
-	 *
224
-	 * Note: This method may not return a meaningful or consistent result across different drivers,
225
-	 * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
226
-	 * columns or sequences.
227
-	 *
228
-	 * @param string $seqName Name of the sequence object from which the ID should be returned.
229
-	 * @return string A string representation of the last inserted ID.
230
-	 */
231
-	public function lastInsertId($seqName = null) {
232
-		if ($seqName) {
233
-			$seqName = $this->replaceTablePrefix($seqName);
234
-		}
235
-		return $this->adapter->lastInsertId($seqName);
236
-	}
237
-
238
-	// internal use
239
-	public function realLastInsertId($seqName = null) {
240
-		return parent::lastInsertId($seqName);
241
-	}
242
-
243
-	/**
244
-	 * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
245
-	 * it is needed that there is also a unique constraint on the values. Then this method will
246
-	 * catch the exception and return 0.
247
-	 *
248
-	 * @param string $table The table name (will replace *PREFIX* with the actual prefix)
249
-	 * @param array $input data that should be inserted into the table  (column name => value)
250
-	 * @param array|null $compare List of values that should be checked for "if not exists"
251
-	 *				If this is null or an empty array, all keys of $input will be compared
252
-	 *				Please note: text fields (clob) must not be used in the compare array
253
-	 * @return int number of inserted rows
254
-	 * @throws \Doctrine\DBAL\DBALException
255
-	 * @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
256
-	 */
257
-	public function insertIfNotExist($table, $input, array $compare = null) {
258
-		return $this->adapter->insertIfNotExist($table, $input, $compare);
259
-	}
260
-
261
-	public function insertIgnoreConflict(string $table, array $values) : int {
262
-		return $this->adapter->insertIgnoreConflict($table, $values);
263
-	}
264
-
265
-	private function getType($value) {
266
-		if (is_bool($value)) {
267
-			return IQueryBuilder::PARAM_BOOL;
268
-		} else if (is_int($value)) {
269
-			return IQueryBuilder::PARAM_INT;
270
-		} else {
271
-			return IQueryBuilder::PARAM_STR;
272
-		}
273
-	}
274
-
275
-	/**
276
-	 * Insert or update a row value
277
-	 *
278
-	 * @param string $table
279
-	 * @param array $keys (column name => value)
280
-	 * @param array $values (column name => value)
281
-	 * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
282
-	 * @return int number of new rows
283
-	 * @throws \Doctrine\DBAL\DBALException
284
-	 * @throws PreConditionNotMetException
285
-	 * @suppress SqlInjectionChecker
286
-	 */
287
-	public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
288
-		try {
289
-			$insertQb = $this->getQueryBuilder();
290
-			$insertQb->insert($table)
291
-				->values(
292
-					array_map(function ($value) use ($insertQb) {
293
-						return $insertQb->createNamedParameter($value, $this->getType($value));
294
-					}, array_merge($keys, $values))
295
-				);
296
-			return $insertQb->execute();
297
-		} catch (ConstraintViolationException $e) {
298
-			// value already exists, try update
299
-			$updateQb = $this->getQueryBuilder();
300
-			$updateQb->update($table);
301
-			foreach ($values as $name => $value) {
302
-				$updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
303
-			}
304
-			$where = $updateQb->expr()->andX();
305
-			$whereValues = array_merge($keys, $updatePreconditionValues);
306
-			foreach ($whereValues as $name => $value) {
307
-				$where->add($updateQb->expr()->eq(
308
-					$name,
309
-					$updateQb->createNamedParameter($value, $this->getType($value)),
310
-					$this->getType($value)
311
-				));
312
-			}
313
-			$updateQb->where($where);
314
-			$affected = $updateQb->execute();
315
-
316
-			if ($affected === 0 && !empty($updatePreconditionValues)) {
317
-				throw new PreConditionNotMetException();
318
-			}
319
-
320
-			return 0;
321
-		}
322
-	}
323
-
324
-	/**
325
-	 * Create an exclusive read+write lock on a table
326
-	 *
327
-	 * @param string $tableName
328
-	 * @throws \BadMethodCallException When trying to acquire a second lock
329
-	 * @since 9.1.0
330
-	 */
331
-	public function lockTable($tableName) {
332
-		if ($this->lockedTable !== null) {
333
-			throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334
-		}
335
-
336
-		$tableName = $this->tablePrefix . $tableName;
337
-		$this->lockedTable = $tableName;
338
-		$this->adapter->lockTable($tableName);
339
-	}
340
-
341
-	/**
342
-	 * Release a previous acquired lock again
343
-	 *
344
-	 * @since 9.1.0
345
-	 */
346
-	public function unlockTable() {
347
-		$this->adapter->unlockTable();
348
-		$this->lockedTable = null;
349
-	}
350
-
351
-	/**
352
-	 * returns the error code and message as a string for logging
353
-	 * works with DoctrineException
354
-	 * @return string
355
-	 */
356
-	public function getError() {
357
-		$msg = $this->errorCode() . ': ';
358
-		$errorInfo = $this->errorInfo();
359
-		if (is_array($errorInfo)) {
360
-			$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
-			$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
362
-			$msg .= 'Driver Message = '.$errorInfo[2];
363
-		}
364
-		return $msg;
365
-	}
366
-
367
-	/**
368
-	 * Drop a table from the database if it exists
369
-	 *
370
-	 * @param string $table table name without the prefix
371
-	 */
372
-	public function dropTable($table) {
373
-		$table = $this->tablePrefix . trim($table);
374
-		$schema = $this->getSchemaManager();
375
-		if($schema->tablesExist([$table])) {
376
-			$schema->dropTable($table);
377
-		}
378
-	}
379
-
380
-	/**
381
-	 * Check if a table exists
382
-	 *
383
-	 * @param string $table table name without the prefix
384
-	 * @return bool
385
-	 */
386
-	public function tableExists($table) {
387
-		$table = $this->tablePrefix . trim($table);
388
-		$schema = $this->getSchemaManager();
389
-		return $schema->tablesExist([$table]);
390
-	}
391
-
392
-	// internal use
393
-	/**
394
-	 * @param string $statement
395
-	 * @return string
396
-	 */
397
-	protected function replaceTablePrefix($statement) {
398
-		return str_replace('*PREFIX*', $this->tablePrefix, $statement);
399
-	}
400
-
401
-	/**
402
-	 * Check if a transaction is active
403
-	 *
404
-	 * @return bool
405
-	 * @since 8.2.0
406
-	 */
407
-	public function inTransaction() {
408
-		return $this->getTransactionNestingLevel() > 0;
409
-	}
410
-
411
-	/**
412
-	 * Escape a parameter to be used in a LIKE query
413
-	 *
414
-	 * @param string $param
415
-	 * @return string
416
-	 */
417
-	public function escapeLikeParameter($param) {
418
-		return addcslashes($param, '\\_%');
419
-	}
420
-
421
-	/**
422
-	 * Check whether or not the current database support 4byte wide unicode
423
-	 *
424
-	 * @return bool
425
-	 * @since 11.0.0
426
-	 */
427
-	public function supports4ByteText() {
428
-		if (!$this->getDatabasePlatform() instanceof MySqlPlatform) {
429
-			return true;
430
-		}
431
-		return $this->getParams()['charset'] === 'utf8mb4';
432
-	}
433
-
434
-
435
-	/**
436
-	 * Create the schema of the connected database
437
-	 *
438
-	 * @return Schema
439
-	 */
440
-	public function createSchema() {
441
-		$schemaManager = new MDB2SchemaManager($this);
442
-		$migrator = $schemaManager->getMigrator();
443
-		return $migrator->createSchema();
444
-	}
445
-
446
-	/**
447
-	 * Migrate the database to the given schema
448
-	 *
449
-	 * @param Schema $toSchema
450
-	 */
451
-	public function migrateToSchema(Schema $toSchema) {
452
-		$schemaManager = new MDB2SchemaManager($this);
453
-		$migrator = $schemaManager->getMigrator();
454
-		$migrator->migrate($toSchema);
455
-	}
50
+    /**
51
+     * @var string $tablePrefix
52
+     */
53
+    protected $tablePrefix;
54
+
55
+    /**
56
+     * @var \OC\DB\Adapter $adapter
57
+     */
58
+    protected $adapter;
59
+
60
+    protected $lockedTable = null;
61
+
62
+    public function connect() {
63
+        try {
64
+            return parent::connect();
65
+        } catch (DBALException $e) {
66
+            // throw a new exception to prevent leaking info from the stacktrace
67
+            throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
68
+        }
69
+    }
70
+
71
+    /**
72
+     * Returns a QueryBuilder for the connection.
73
+     *
74
+     * @return \OCP\DB\QueryBuilder\IQueryBuilder
75
+     */
76
+    public function getQueryBuilder() {
77
+        return new QueryBuilder(
78
+            $this,
79
+            \OC::$server->getSystemConfig(),
80
+            \OC::$server->getLogger()
81
+        );
82
+    }
83
+
84
+    /**
85
+     * Gets the QueryBuilder for the connection.
86
+     *
87
+     * @return \Doctrine\DBAL\Query\QueryBuilder
88
+     * @deprecated please use $this->getQueryBuilder() instead
89
+     */
90
+    public function createQueryBuilder() {
91
+        $backtrace = $this->getCallerBacktrace();
92
+        \OC::$server->getLogger()->debug('Doctrine QueryBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
93
+        return parent::createQueryBuilder();
94
+    }
95
+
96
+    /**
97
+     * Gets the ExpressionBuilder for the connection.
98
+     *
99
+     * @return \Doctrine\DBAL\Query\Expression\ExpressionBuilder
100
+     * @deprecated please use $this->getQueryBuilder()->expr() instead
101
+     */
102
+    public function getExpressionBuilder() {
103
+        $backtrace = $this->getCallerBacktrace();
104
+        \OC::$server->getLogger()->debug('Doctrine ExpressionBuilder retrieved in {backtrace}', ['app' => 'core', 'backtrace' => $backtrace]);
105
+        return parent::getExpressionBuilder();
106
+    }
107
+
108
+    /**
109
+     * Get the file and line that called the method where `getCallerBacktrace()` was used
110
+     *
111
+     * @return string
112
+     */
113
+    protected function getCallerBacktrace() {
114
+        $traces = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 2);
115
+
116
+        // 0 is the method where we use `getCallerBacktrace`
117
+        // 1 is the target method which uses the method we want to log
118
+        if (isset($traces[1])) {
119
+            return $traces[1]['file'] . ':' . $traces[1]['line'];
120
+        }
121
+
122
+        return '';
123
+    }
124
+
125
+    /**
126
+     * @return string
127
+     */
128
+    public function getPrefix() {
129
+        return $this->tablePrefix;
130
+    }
131
+
132
+    /**
133
+     * Initializes a new instance of the Connection class.
134
+     *
135
+     * @param array $params  The connection parameters.
136
+     * @param \Doctrine\DBAL\Driver $driver
137
+     * @param \Doctrine\DBAL\Configuration $config
138
+     * @param \Doctrine\Common\EventManager $eventManager
139
+     * @throws \Exception
140
+     */
141
+    public function __construct(array $params, Driver $driver, Configuration $config = null,
142
+        EventManager $eventManager = null)
143
+    {
144
+        if (!isset($params['adapter'])) {
145
+            throw new \Exception('adapter not set');
146
+        }
147
+        if (!isset($params['tablePrefix'])) {
148
+            throw new \Exception('tablePrefix not set');
149
+        }
150
+        parent::__construct($params, $driver, $config, $eventManager);
151
+        $this->adapter = new $params['adapter']($this);
152
+        $this->tablePrefix = $params['tablePrefix'];
153
+    }
154
+
155
+    /**
156
+     * Prepares an SQL statement.
157
+     *
158
+     * @param string $statement The SQL statement to prepare.
159
+     * @param int $limit
160
+     * @param int $offset
161
+     * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162
+     */
163
+    public function prepare($statement, $limit=null, $offset=null) {
164
+        if ($limit === -1) {
165
+            $limit = null;
166
+        }
167
+        if (!is_null($limit)) {
168
+            $platform = $this->getDatabasePlatform();
169
+            $statement = $platform->modifyLimitQuery($statement, $limit, $offset);
170
+        }
171
+        $statement = $this->replaceTablePrefix($statement);
172
+        $statement = $this->adapter->fixupStatement($statement);
173
+
174
+        return parent::prepare($statement);
175
+    }
176
+
177
+    /**
178
+     * Executes an, optionally parametrized, SQL query.
179
+     *
180
+     * If the query is parametrized, a prepared statement is used.
181
+     * If an SQLLogger is configured, the execution is logged.
182
+     *
183
+     * @param string                                      $query  The SQL query to execute.
184
+     * @param array                                       $params The parameters to bind to the query, if any.
185
+     * @param array                                       $types  The types the previous parameters are in.
186
+     * @param \Doctrine\DBAL\Cache\QueryCacheProfile|null $qcp    The query cache profile, optional.
187
+     *
188
+     * @return \Doctrine\DBAL\Driver\Statement The executed statement.
189
+     *
190
+     * @throws \Doctrine\DBAL\DBALException
191
+     */
192
+    public function executeQuery($query, array $params = [], $types = [], QueryCacheProfile $qcp = null)
193
+    {
194
+        $query = $this->replaceTablePrefix($query);
195
+        $query = $this->adapter->fixupStatement($query);
196
+        return parent::executeQuery($query, $params, $types, $qcp);
197
+    }
198
+
199
+    /**
200
+     * Executes an SQL INSERT/UPDATE/DELETE query with the given parameters
201
+     * and returns the number of affected rows.
202
+     *
203
+     * This method supports PDO binding types as well as DBAL mapping types.
204
+     *
205
+     * @param string $query  The SQL query.
206
+     * @param array  $params The query parameters.
207
+     * @param array  $types  The parameter types.
208
+     *
209
+     * @return integer The number of affected rows.
210
+     *
211
+     * @throws \Doctrine\DBAL\DBALException
212
+     */
213
+    public function executeUpdate($query, array $params = [], array $types = [])
214
+    {
215
+        $query = $this->replaceTablePrefix($query);
216
+        $query = $this->adapter->fixupStatement($query);
217
+        return parent::executeUpdate($query, $params, $types);
218
+    }
219
+
220
+    /**
221
+     * Returns the ID of the last inserted row, or the last value from a sequence object,
222
+     * depending on the underlying driver.
223
+     *
224
+     * Note: This method may not return a meaningful or consistent result across different drivers,
225
+     * because the underlying database may not even support the notion of AUTO_INCREMENT/IDENTITY
226
+     * columns or sequences.
227
+     *
228
+     * @param string $seqName Name of the sequence object from which the ID should be returned.
229
+     * @return string A string representation of the last inserted ID.
230
+     */
231
+    public function lastInsertId($seqName = null) {
232
+        if ($seqName) {
233
+            $seqName = $this->replaceTablePrefix($seqName);
234
+        }
235
+        return $this->adapter->lastInsertId($seqName);
236
+    }
237
+
238
+    // internal use
239
+    public function realLastInsertId($seqName = null) {
240
+        return parent::lastInsertId($seqName);
241
+    }
242
+
243
+    /**
244
+     * Insert a row if the matching row does not exists. To accomplish proper race condition avoidance
245
+     * it is needed that there is also a unique constraint on the values. Then this method will
246
+     * catch the exception and return 0.
247
+     *
248
+     * @param string $table The table name (will replace *PREFIX* with the actual prefix)
249
+     * @param array $input data that should be inserted into the table  (column name => value)
250
+     * @param array|null $compare List of values that should be checked for "if not exists"
251
+     *				If this is null or an empty array, all keys of $input will be compared
252
+     *				Please note: text fields (clob) must not be used in the compare array
253
+     * @return int number of inserted rows
254
+     * @throws \Doctrine\DBAL\DBALException
255
+     * @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
256
+     */
257
+    public function insertIfNotExist($table, $input, array $compare = null) {
258
+        return $this->adapter->insertIfNotExist($table, $input, $compare);
259
+    }
260
+
261
+    public function insertIgnoreConflict(string $table, array $values) : int {
262
+        return $this->adapter->insertIgnoreConflict($table, $values);
263
+    }
264
+
265
+    private function getType($value) {
266
+        if (is_bool($value)) {
267
+            return IQueryBuilder::PARAM_BOOL;
268
+        } else if (is_int($value)) {
269
+            return IQueryBuilder::PARAM_INT;
270
+        } else {
271
+            return IQueryBuilder::PARAM_STR;
272
+        }
273
+    }
274
+
275
+    /**
276
+     * Insert or update a row value
277
+     *
278
+     * @param string $table
279
+     * @param array $keys (column name => value)
280
+     * @param array $values (column name => value)
281
+     * @param array $updatePreconditionValues ensure values match preconditions (column name => value)
282
+     * @return int number of new rows
283
+     * @throws \Doctrine\DBAL\DBALException
284
+     * @throws PreConditionNotMetException
285
+     * @suppress SqlInjectionChecker
286
+     */
287
+    public function setValues($table, array $keys, array $values, array $updatePreconditionValues = []) {
288
+        try {
289
+            $insertQb = $this->getQueryBuilder();
290
+            $insertQb->insert($table)
291
+                ->values(
292
+                    array_map(function ($value) use ($insertQb) {
293
+                        return $insertQb->createNamedParameter($value, $this->getType($value));
294
+                    }, array_merge($keys, $values))
295
+                );
296
+            return $insertQb->execute();
297
+        } catch (ConstraintViolationException $e) {
298
+            // value already exists, try update
299
+            $updateQb = $this->getQueryBuilder();
300
+            $updateQb->update($table);
301
+            foreach ($values as $name => $value) {
302
+                $updateQb->set($name, $updateQb->createNamedParameter($value, $this->getType($value)));
303
+            }
304
+            $where = $updateQb->expr()->andX();
305
+            $whereValues = array_merge($keys, $updatePreconditionValues);
306
+            foreach ($whereValues as $name => $value) {
307
+                $where->add($updateQb->expr()->eq(
308
+                    $name,
309
+                    $updateQb->createNamedParameter($value, $this->getType($value)),
310
+                    $this->getType($value)
311
+                ));
312
+            }
313
+            $updateQb->where($where);
314
+            $affected = $updateQb->execute();
315
+
316
+            if ($affected === 0 && !empty($updatePreconditionValues)) {
317
+                throw new PreConditionNotMetException();
318
+            }
319
+
320
+            return 0;
321
+        }
322
+    }
323
+
324
+    /**
325
+     * Create an exclusive read+write lock on a table
326
+     *
327
+     * @param string $tableName
328
+     * @throws \BadMethodCallException When trying to acquire a second lock
329
+     * @since 9.1.0
330
+     */
331
+    public function lockTable($tableName) {
332
+        if ($this->lockedTable !== null) {
333
+            throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334
+        }
335
+
336
+        $tableName = $this->tablePrefix . $tableName;
337
+        $this->lockedTable = $tableName;
338
+        $this->adapter->lockTable($tableName);
339
+    }
340
+
341
+    /**
342
+     * Release a previous acquired lock again
343
+     *
344
+     * @since 9.1.0
345
+     */
346
+    public function unlockTable() {
347
+        $this->adapter->unlockTable();
348
+        $this->lockedTable = null;
349
+    }
350
+
351
+    /**
352
+     * returns the error code and message as a string for logging
353
+     * works with DoctrineException
354
+     * @return string
355
+     */
356
+    public function getError() {
357
+        $msg = $this->errorCode() . ': ';
358
+        $errorInfo = $this->errorInfo();
359
+        if (is_array($errorInfo)) {
360
+            $msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
+            $msg .= 'Driver Code = '.$errorInfo[1] . ', ';
362
+            $msg .= 'Driver Message = '.$errorInfo[2];
363
+        }
364
+        return $msg;
365
+    }
366
+
367
+    /**
368
+     * Drop a table from the database if it exists
369
+     *
370
+     * @param string $table table name without the prefix
371
+     */
372
+    public function dropTable($table) {
373
+        $table = $this->tablePrefix . trim($table);
374
+        $schema = $this->getSchemaManager();
375
+        if($schema->tablesExist([$table])) {
376
+            $schema->dropTable($table);
377
+        }
378
+    }
379
+
380
+    /**
381
+     * Check if a table exists
382
+     *
383
+     * @param string $table table name without the prefix
384
+     * @return bool
385
+     */
386
+    public function tableExists($table) {
387
+        $table = $this->tablePrefix . trim($table);
388
+        $schema = $this->getSchemaManager();
389
+        return $schema->tablesExist([$table]);
390
+    }
391
+
392
+    // internal use
393
+    /**
394
+     * @param string $statement
395
+     * @return string
396
+     */
397
+    protected function replaceTablePrefix($statement) {
398
+        return str_replace('*PREFIX*', $this->tablePrefix, $statement);
399
+    }
400
+
401
+    /**
402
+     * Check if a transaction is active
403
+     *
404
+     * @return bool
405
+     * @since 8.2.0
406
+     */
407
+    public function inTransaction() {
408
+        return $this->getTransactionNestingLevel() > 0;
409
+    }
410
+
411
+    /**
412
+     * Escape a parameter to be used in a LIKE query
413
+     *
414
+     * @param string $param
415
+     * @return string
416
+     */
417
+    public function escapeLikeParameter($param) {
418
+        return addcslashes($param, '\\_%');
419
+    }
420
+
421
+    /**
422
+     * Check whether or not the current database support 4byte wide unicode
423
+     *
424
+     * @return bool
425
+     * @since 11.0.0
426
+     */
427
+    public function supports4ByteText() {
428
+        if (!$this->getDatabasePlatform() instanceof MySqlPlatform) {
429
+            return true;
430
+        }
431
+        return $this->getParams()['charset'] === 'utf8mb4';
432
+    }
433
+
434
+
435
+    /**
436
+     * Create the schema of the connected database
437
+     *
438
+     * @return Schema
439
+     */
440
+    public function createSchema() {
441
+        $schemaManager = new MDB2SchemaManager($this);
442
+        $migrator = $schemaManager->getMigrator();
443
+        return $migrator->createSchema();
444
+    }
445
+
446
+    /**
447
+     * Migrate the database to the given schema
448
+     *
449
+     * @param Schema $toSchema
450
+     */
451
+    public function migrateToSchema(Schema $toSchema) {
452
+        $schemaManager = new MDB2SchemaManager($this);
453
+        $migrator = $schemaManager->getMigrator();
454
+        $migrator->migrate($toSchema);
455
+    }
456 456
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -64,7 +64,7 @@  discard block
 block discarded – undo
64 64
 			return parent::connect();
65 65
 		} catch (DBALException $e) {
66 66
 			// throw a new exception to prevent leaking info from the stacktrace
67
-			throw new DBALException('Failed to connect to the database: ' . $e->getMessage(), $e->getCode());
67
+			throw new DBALException('Failed to connect to the database: '.$e->getMessage(), $e->getCode());
68 68
 		}
69 69
 	}
70 70
 
@@ -116,7 +116,7 @@  discard block
 block discarded – undo
116 116
 		// 0 is the method where we use `getCallerBacktrace`
117 117
 		// 1 is the target method which uses the method we want to log
118 118
 		if (isset($traces[1])) {
119
-			return $traces[1]['file'] . ':' . $traces[1]['line'];
119
+			return $traces[1]['file'].':'.$traces[1]['line'];
120 120
 		}
121 121
 
122 122
 		return '';
@@ -160,7 +160,7 @@  discard block
 block discarded – undo
160 160
 	 * @param int $offset
161 161
 	 * @return \Doctrine\DBAL\Driver\Statement The prepared statement.
162 162
 	 */
163
-	public function prepare($statement, $limit=null, $offset=null) {
163
+	public function prepare($statement, $limit = null, $offset = null) {
164 164
 		if ($limit === -1) {
165 165
 			$limit = null;
166 166
 		}
@@ -289,7 +289,7 @@  discard block
 block discarded – undo
289 289
 			$insertQb = $this->getQueryBuilder();
290 290
 			$insertQb->insert($table)
291 291
 				->values(
292
-					array_map(function ($value) use ($insertQb) {
292
+					array_map(function($value) use ($insertQb) {
293 293
 						return $insertQb->createNamedParameter($value, $this->getType($value));
294 294
 					}, array_merge($keys, $values))
295 295
 				);
@@ -333,7 +333,7 @@  discard block
 block discarded – undo
333 333
 			throw new \BadMethodCallException('Can not lock a new table until the previous lock is released.');
334 334
 		}
335 335
 
336
-		$tableName = $this->tablePrefix . $tableName;
336
+		$tableName = $this->tablePrefix.$tableName;
337 337
 		$this->lockedTable = $tableName;
338 338
 		$this->adapter->lockTable($tableName);
339 339
 	}
@@ -354,11 +354,11 @@  discard block
 block discarded – undo
354 354
 	 * @return string
355 355
 	 */
356 356
 	public function getError() {
357
-		$msg = $this->errorCode() . ': ';
357
+		$msg = $this->errorCode().': ';
358 358
 		$errorInfo = $this->errorInfo();
359 359
 		if (is_array($errorInfo)) {
360
-			$msg .= 'SQLSTATE = '.$errorInfo[0] . ', ';
361
-			$msg .= 'Driver Code = '.$errorInfo[1] . ', ';
360
+			$msg .= 'SQLSTATE = '.$errorInfo[0].', ';
361
+			$msg .= 'Driver Code = '.$errorInfo[1].', ';
362 362
 			$msg .= 'Driver Message = '.$errorInfo[2];
363 363
 		}
364 364
 		return $msg;
@@ -370,9 +370,9 @@  discard block
 block discarded – undo
370 370
 	 * @param string $table table name without the prefix
371 371
 	 */
372 372
 	public function dropTable($table) {
373
-		$table = $this->tablePrefix . trim($table);
373
+		$table = $this->tablePrefix.trim($table);
374 374
 		$schema = $this->getSchemaManager();
375
-		if($schema->tablesExist([$table])) {
375
+		if ($schema->tablesExist([$table])) {
376 376
 			$schema->dropTable($table);
377 377
 		}
378 378
 	}
@@ -384,7 +384,7 @@  discard block
 block discarded – undo
384 384
 	 * @return bool
385 385
 	 */
386 386
 	public function tableExists($table) {
387
-		$table = $this->tablePrefix . trim($table);
387
+		$table = $this->tablePrefix.trim($table);
388 388
 		$schema = $this->getSchemaManager();
389 389
 		return $schema->tablesExist([$table]);
390 390
 	}
Please login to merge, or discard this patch.
lib/private/DB/AdapterPgSql.php 2 patches
Indentation   +35 added lines, -35 removed lines patch added patch discarded remove patch
@@ -27,46 +27,46 @@
 block discarded – undo
27 27
 namespace OC\DB;
28 28
 
29 29
 class AdapterPgSql extends Adapter {
30
-	protected $compatModePre9_5 = null;
30
+    protected $compatModePre9_5 = null;
31 31
 
32
-	public function lastInsertId($table) {
33
-		return $this->conn->fetchColumn('SELECT lastval()');
34
-	}
32
+    public function lastInsertId($table) {
33
+        return $this->conn->fetchColumn('SELECT lastval()');
34
+    }
35 35
 
36
-	const UNIX_TIMESTAMP_REPLACEMENT = 'cast(extract(epoch from current_timestamp) as integer)';
37
-	public function fixupStatement($statement) {
38
-		$statement = str_replace('`', '"', $statement);
39
-		$statement = str_ireplace('UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement);
40
-		return $statement;
41
-	}
36
+    const UNIX_TIMESTAMP_REPLACEMENT = 'cast(extract(epoch from current_timestamp) as integer)';
37
+    public function fixupStatement($statement) {
38
+        $statement = str_replace('`', '"', $statement);
39
+        $statement = str_ireplace('UNIX_TIMESTAMP()', self::UNIX_TIMESTAMP_REPLACEMENT, $statement);
40
+        return $statement;
41
+    }
42 42
 
43
-	/**
44
-	 * @suppress SqlInjectionChecker
45
-	 */
46
-	public function insertIgnoreConflict(string $table,array $values) : int {
47
-		if($this->isPre9_5CompatMode() === true) {
48
-			return parent::insertIgnoreConflict($table, $values);
49
-		}
43
+    /**
44
+     * @suppress SqlInjectionChecker
45
+     */
46
+    public function insertIgnoreConflict(string $table,array $values) : int {
47
+        if($this->isPre9_5CompatMode() === true) {
48
+            return parent::insertIgnoreConflict($table, $values);
49
+        }
50 50
 
51
-		// "upsert" is only available since PgSQL 9.5, but the generic way
52
-		// would leave error logs in the DB.
53
-		$builder = $this->conn->getQueryBuilder();
54
-		$builder->insert($table);
55
-		foreach ($values as $key => $value) {
56
-			$builder->setValue($key, $builder->createNamedParameter($value));
57
-		}
58
-		$queryString = $builder->getSQL() . ' ON CONFLICT DO NOTHING';
59
-		return $this->conn->executeUpdate($queryString, $builder->getParameters(), $builder->getParameterTypes());
60
-	}
51
+        // "upsert" is only available since PgSQL 9.5, but the generic way
52
+        // would leave error logs in the DB.
53
+        $builder = $this->conn->getQueryBuilder();
54
+        $builder->insert($table);
55
+        foreach ($values as $key => $value) {
56
+            $builder->setValue($key, $builder->createNamedParameter($value));
57
+        }
58
+        $queryString = $builder->getSQL() . ' ON CONFLICT DO NOTHING';
59
+        return $this->conn->executeUpdate($queryString, $builder->getParameters(), $builder->getParameterTypes());
60
+    }
61 61
 
62
-	protected function isPre9_5CompatMode(): bool {
63
-		if($this->compatModePre9_5 !== null) {
64
-			return $this->compatModePre9_5;
65
-		}
62
+    protected function isPre9_5CompatMode(): bool {
63
+        if($this->compatModePre9_5 !== null) {
64
+            return $this->compatModePre9_5;
65
+        }
66 66
 
67
-		$version = $this->conn->fetchColumn('SHOW SERVER_VERSION');
68
-		$this->compatModePre9_5 = version_compare($version, '9.5', '<');
67
+        $version = $this->conn->fetchColumn('SHOW SERVER_VERSION');
68
+        $this->compatModePre9_5 = version_compare($version, '9.5', '<');
69 69
 
70
-		return $this->compatModePre9_5;
71
-	}
70
+        return $this->compatModePre9_5;
71
+    }
72 72
 }
Please login to merge, or discard this patch.
Spacing   +4 added lines, -4 removed lines patch added patch discarded remove patch
@@ -43,8 +43,8 @@  discard block
 block discarded – undo
43 43
 	/**
44 44
 	 * @suppress SqlInjectionChecker
45 45
 	 */
46
-	public function insertIgnoreConflict(string $table,array $values) : int {
47
-		if($this->isPre9_5CompatMode() === true) {
46
+	public function insertIgnoreConflict(string $table, array $values) : int {
47
+		if ($this->isPre9_5CompatMode() === true) {
48 48
 			return parent::insertIgnoreConflict($table, $values);
49 49
 		}
50 50
 
@@ -55,12 +55,12 @@  discard block
 block discarded – undo
55 55
 		foreach ($values as $key => $value) {
56 56
 			$builder->setValue($key, $builder->createNamedParameter($value));
57 57
 		}
58
-		$queryString = $builder->getSQL() . ' ON CONFLICT DO NOTHING';
58
+		$queryString = $builder->getSQL().' ON CONFLICT DO NOTHING';
59 59
 		return $this->conn->executeUpdate($queryString, $builder->getParameters(), $builder->getParameterTypes());
60 60
 	}
61 61
 
62 62
 	protected function isPre9_5CompatMode(): bool {
63
-		if($this->compatModePre9_5 !== null) {
63
+		if ($this->compatModePre9_5 !== null) {
64 64
 			return $this->compatModePre9_5;
65 65
 		}
66 66
 
Please login to merge, or discard this patch.