Completed
Pull Request — master (#4146)
by Robin
17:01
created
apps/dav/lib/Connector/Sabre/CommentPropertiesPlugin.php 1 patch
Indentation   +127 added lines, -127 removed lines patch added patch discarded remove patch
@@ -29,132 +29,132 @@
 block discarded – undo
29 29
 
30 30
 class CommentPropertiesPlugin extends ServerPlugin {
31 31
 
32
-	const PROPERTY_NAME_HREF   = '{http://owncloud.org/ns}comments-href';
33
-	const PROPERTY_NAME_COUNT  = '{http://owncloud.org/ns}comments-count';
34
-	const PROPERTY_NAME_UNREAD = '{http://owncloud.org/ns}comments-unread';
35
-
36
-	/** @var  \Sabre\DAV\Server */
37
-	protected $server;
38
-
39
-	/** @var ICommentsManager */
40
-	private $commentsManager;
41
-
42
-	/** @var IUserSession */
43
-	private $userSession;
44
-
45
-	private $cachedUnreadCount = [];
46
-
47
-	private $cachedFolders = [];
48
-
49
-	public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) {
50
-		$this->commentsManager = $commentsManager;
51
-		$this->userSession = $userSession;
52
-	}
53
-
54
-	/**
55
-	 * This initializes the plugin.
56
-	 *
57
-	 * This function is called by Sabre\DAV\Server, after
58
-	 * addPlugin is called.
59
-	 *
60
-	 * This method should set up the required event subscriptions.
61
-	 *
62
-	 * @param \Sabre\DAV\Server $server
63
-	 * @return void
64
-	 */
65
-	function initialize(\Sabre\DAV\Server $server) {
66
-		$this->server = $server;
67
-		$this->server->on('propFind', array($this, 'handleGetProperties'));
68
-	}
69
-
70
-	/**
71
-	 * Adds tags and favorites properties to the response,
72
-	 * if requested.
73
-	 *
74
-	 * @param PropFind $propFind
75
-	 * @param \Sabre\DAV\INode $node
76
-	 * @return void
77
-	 */
78
-	public function handleGetProperties(
79
-		PropFind $propFind,
80
-		\Sabre\DAV\INode $node
81
-	) {
82
-		if (!($node instanceof File) && !($node instanceof Directory)) {
83
-			return;
84
-		}
85
-
86
-		// need prefetch ?
87
-		if ($node instanceof \OCA\DAV\Connector\Sabre\Directory
88
-			&& $propFind->getDepth() !== 0
89
-			&& !is_null($propFind->getStatus(self::PROPERTY_NAME_UNREAD))
90
-		) {
91
-			$unreadCounts = $this->commentsManager->getNumberOfUnreadCommentsForFolder($node->getId(), $this->userSession->getUser());
92
-			$this->cachedFolders[] = $node->getPath();
93
-			foreach ($unreadCounts as $id => $count) {
94
-				$this->cachedUnreadCount[$id] = $count;
95
-			}
96
-		}
97
-
98
-		$propFind->handle(self::PROPERTY_NAME_COUNT, function() use ($node) {
99
-			return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()));
100
-		});
101
-
102
-		$propFind->handle(self::PROPERTY_NAME_HREF, function() use ($node) {
103
-			return $this->getCommentsLink($node);
104
-		});
105
-
106
-		$propFind->handle(self::PROPERTY_NAME_UNREAD, function() use ($node) {
107
-			if (isset($this->cachedUnreadCount[$node->getId()])) {
108
-				return $this->cachedUnreadCount[$node->getId()];
109
-			} else {
110
-				list($parentPath,) = \Sabre\Uri\split($node->getPath());
111
-				if ($parentPath === '') {
112
-					$parentPath = '/';
113
-				}
114
-				// if we already cached the folder this file is in we know there are no shares for this file
115
-				if (array_search($parentPath, $this->cachedFolders) === false) {
116
-					return $this->getUnreadCount($node);
117
-				} else {
118
-					return 0;
119
-				}
120
-			}
121
-		});
122
-	}
123
-
124
-	/**
125
-	 * returns a reference to the comments node
126
-	 *
127
-	 * @param Node $node
128
-	 * @return mixed|string
129
-	 */
130
-	public function getCommentsLink(Node $node) {
131
-		$href =  $this->server->getBaseUri();
132
-		$entryPoint = strpos($href, '/remote.php/');
133
-		if($entryPoint === false) {
134
-			// in case we end up somewhere else, unexpectedly.
135
-			return null;
136
-		}
137
-		$commentsPart = 'dav/comments/files/' . rawurldecode($node->getId());
138
-		$href = substr_replace($href, $commentsPart, $entryPoint + strlen('/remote.php/'));
139
-		return $href;
140
-	}
141
-
142
-	/**
143
-	 * returns the number of unread comments for the currently logged in user
144
-	 * on the given file or directory node
145
-	 *
146
-	 * @param Node $node
147
-	 * @return Int|null
148
-	 */
149
-	public function getUnreadCount(Node $node) {
150
-		$user = $this->userSession->getUser();
151
-		if(is_null($user)) {
152
-			return null;
153
-		}
154
-
155
-		$lastRead = $this->commentsManager->getReadMark('files', strval($node->getId()), $user);
156
-
157
-		return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()), $lastRead);
158
-	}
32
+    const PROPERTY_NAME_HREF   = '{http://owncloud.org/ns}comments-href';
33
+    const PROPERTY_NAME_COUNT  = '{http://owncloud.org/ns}comments-count';
34
+    const PROPERTY_NAME_UNREAD = '{http://owncloud.org/ns}comments-unread';
35
+
36
+    /** @var  \Sabre\DAV\Server */
37
+    protected $server;
38
+
39
+    /** @var ICommentsManager */
40
+    private $commentsManager;
41
+
42
+    /** @var IUserSession */
43
+    private $userSession;
44
+
45
+    private $cachedUnreadCount = [];
46
+
47
+    private $cachedFolders = [];
48
+
49
+    public function __construct(ICommentsManager $commentsManager, IUserSession $userSession) {
50
+        $this->commentsManager = $commentsManager;
51
+        $this->userSession = $userSession;
52
+    }
53
+
54
+    /**
55
+     * This initializes the plugin.
56
+     *
57
+     * This function is called by Sabre\DAV\Server, after
58
+     * addPlugin is called.
59
+     *
60
+     * This method should set up the required event subscriptions.
61
+     *
62
+     * @param \Sabre\DAV\Server $server
63
+     * @return void
64
+     */
65
+    function initialize(\Sabre\DAV\Server $server) {
66
+        $this->server = $server;
67
+        $this->server->on('propFind', array($this, 'handleGetProperties'));
68
+    }
69
+
70
+    /**
71
+     * Adds tags and favorites properties to the response,
72
+     * if requested.
73
+     *
74
+     * @param PropFind $propFind
75
+     * @param \Sabre\DAV\INode $node
76
+     * @return void
77
+     */
78
+    public function handleGetProperties(
79
+        PropFind $propFind,
80
+        \Sabre\DAV\INode $node
81
+    ) {
82
+        if (!($node instanceof File) && !($node instanceof Directory)) {
83
+            return;
84
+        }
85
+
86
+        // need prefetch ?
87
+        if ($node instanceof \OCA\DAV\Connector\Sabre\Directory
88
+            && $propFind->getDepth() !== 0
89
+            && !is_null($propFind->getStatus(self::PROPERTY_NAME_UNREAD))
90
+        ) {
91
+            $unreadCounts = $this->commentsManager->getNumberOfUnreadCommentsForFolder($node->getId(), $this->userSession->getUser());
92
+            $this->cachedFolders[] = $node->getPath();
93
+            foreach ($unreadCounts as $id => $count) {
94
+                $this->cachedUnreadCount[$id] = $count;
95
+            }
96
+        }
97
+
98
+        $propFind->handle(self::PROPERTY_NAME_COUNT, function() use ($node) {
99
+            return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()));
100
+        });
101
+
102
+        $propFind->handle(self::PROPERTY_NAME_HREF, function() use ($node) {
103
+            return $this->getCommentsLink($node);
104
+        });
105
+
106
+        $propFind->handle(self::PROPERTY_NAME_UNREAD, function() use ($node) {
107
+            if (isset($this->cachedUnreadCount[$node->getId()])) {
108
+                return $this->cachedUnreadCount[$node->getId()];
109
+            } else {
110
+                list($parentPath,) = \Sabre\Uri\split($node->getPath());
111
+                if ($parentPath === '') {
112
+                    $parentPath = '/';
113
+                }
114
+                // if we already cached the folder this file is in we know there are no shares for this file
115
+                if (array_search($parentPath, $this->cachedFolders) === false) {
116
+                    return $this->getUnreadCount($node);
117
+                } else {
118
+                    return 0;
119
+                }
120
+            }
121
+        });
122
+    }
123
+
124
+    /**
125
+     * returns a reference to the comments node
126
+     *
127
+     * @param Node $node
128
+     * @return mixed|string
129
+     */
130
+    public function getCommentsLink(Node $node) {
131
+        $href =  $this->server->getBaseUri();
132
+        $entryPoint = strpos($href, '/remote.php/');
133
+        if($entryPoint === false) {
134
+            // in case we end up somewhere else, unexpectedly.
135
+            return null;
136
+        }
137
+        $commentsPart = 'dav/comments/files/' . rawurldecode($node->getId());
138
+        $href = substr_replace($href, $commentsPart, $entryPoint + strlen('/remote.php/'));
139
+        return $href;
140
+    }
141
+
142
+    /**
143
+     * returns the number of unread comments for the currently logged in user
144
+     * on the given file or directory node
145
+     *
146
+     * @param Node $node
147
+     * @return Int|null
148
+     */
149
+    public function getUnreadCount(Node $node) {
150
+        $user = $this->userSession->getUser();
151
+        if(is_null($user)) {
152
+            return null;
153
+        }
154
+
155
+        $lastRead = $this->commentsManager->getReadMark('files', strval($node->getId()), $user);
156
+
157
+        return $this->commentsManager->getNumberOfCommentsForObject('files', strval($node->getId()), $lastRead);
158
+    }
159 159
 
160 160
 }
Please login to merge, or discard this patch.
lib/public/Comments/ICommentsManager.php 1 patch
Indentation   +233 added lines, -233 removed lines patch added patch discarded remove patch
@@ -35,255 +35,255 @@
 block discarded – undo
35 35
  */
36 36
 interface ICommentsManager {
37 37
 
38
-	/**
39
-	 * @const DELETED_USER type and id for a user that has been deleted
40
-	 * @see deleteReferencesOfActor
41
-	 * @since 9.0.0
42
-	 *
43
-	 * To be used as replacement for user type actors in deleteReferencesOfActor().
44
-	 *
45
-	 * User interfaces shall show "Deleted user" as display name, if needed.
46
-	 */
47
-	const DELETED_USER = 'deleted_users';
38
+    /**
39
+     * @const DELETED_USER type and id for a user that has been deleted
40
+     * @see deleteReferencesOfActor
41
+     * @since 9.0.0
42
+     *
43
+     * To be used as replacement for user type actors in deleteReferencesOfActor().
44
+     *
45
+     * User interfaces shall show "Deleted user" as display name, if needed.
46
+     */
47
+    const DELETED_USER = 'deleted_users';
48 48
 
49
-	/**
50
-	 * returns a comment instance
51
-	 *
52
-	 * @param string $id the ID of the comment
53
-	 * @return IComment
54
-	 * @throws NotFoundException
55
-	 * @since 9.0.0
56
-	 */
57
-	public function get($id);
49
+    /**
50
+     * returns a comment instance
51
+     *
52
+     * @param string $id the ID of the comment
53
+     * @return IComment
54
+     * @throws NotFoundException
55
+     * @since 9.0.0
56
+     */
57
+    public function get($id);
58 58
 
59
-	/**
60
-	 * returns the comment specified by the id and all it's child comments
61
-	 *
62
-	 * @param string $id
63
-	 * @param int $limit max number of entries to return, 0 returns all
64
-	 * @param int $offset the start entry
65
-	 * @return array
66
-	 * @since 9.0.0
67
-	 *
68
-	 * The return array looks like this
69
-	 * [
70
-	 * 	 'comment' => IComment, // root comment
71
-	 *   'replies' =>
72
-	 *   [
73
-	 *     0 =>
74
-	 *     [
75
-	 *       'comment' => IComment,
76
-	 *       'replies' =>
77
-	 *       [
78
-	 *         0 =>
79
-	 *         [
80
-	 *           'comment' => IComment,
81
-	 *           'replies' => [ … ]
82
-	 *         ],
83
-	 *         …
84
-	 *       ]
85
-	 *     ]
86
-	 *     1 =>
87
-	 *     [
88
-	 *       'comment' => IComment,
89
-	 *       'replies'=> [ … ]
90
-	 *     ],
91
-	 *     …
92
-	 *   ]
93
-	 * ]
94
-	 */
95
-	public function getTree($id, $limit = 0, $offset = 0);
59
+    /**
60
+     * returns the comment specified by the id and all it's child comments
61
+     *
62
+     * @param string $id
63
+     * @param int $limit max number of entries to return, 0 returns all
64
+     * @param int $offset the start entry
65
+     * @return array
66
+     * @since 9.0.0
67
+     *
68
+     * The return array looks like this
69
+     * [
70
+     * 	 'comment' => IComment, // root comment
71
+     *   'replies' =>
72
+     *   [
73
+     *     0 =>
74
+     *     [
75
+     *       'comment' => IComment,
76
+     *       'replies' =>
77
+     *       [
78
+     *         0 =>
79
+     *         [
80
+     *           'comment' => IComment,
81
+     *           'replies' => [ … ]
82
+     *         ],
83
+     *         …
84
+     *       ]
85
+     *     ]
86
+     *     1 =>
87
+     *     [
88
+     *       'comment' => IComment,
89
+     *       'replies'=> [ … ]
90
+     *     ],
91
+     *     …
92
+     *   ]
93
+     * ]
94
+     */
95
+    public function getTree($id, $limit = 0, $offset = 0);
96 96
 
97
-	/**
98
-	 * returns comments for a specific object (e.g. a file).
99
-	 *
100
-	 * The sort order is always newest to oldest.
101
-	 *
102
-	 * @param string $objectType the object type, e.g. 'files'
103
-	 * @param string $objectId the id of the object
104
-	 * @param int $limit optional, number of maximum comments to be returned. if
105
-	 * not specified, all comments are returned.
106
-	 * @param int $offset optional, starting point
107
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
108
-	 * that may be returned
109
-	 * @return IComment[]
110
-	 * @since 9.0.0
111
-	 */
112
-	public function getForObject(
113
-			$objectType,
114
-			$objectId,
115
-			$limit = 0,
116
-			$offset = 0,
117
-			\DateTime $notOlderThan = null
118
-	);
97
+    /**
98
+     * returns comments for a specific object (e.g. a file).
99
+     *
100
+     * The sort order is always newest to oldest.
101
+     *
102
+     * @param string $objectType the object type, e.g. 'files'
103
+     * @param string $objectId the id of the object
104
+     * @param int $limit optional, number of maximum comments to be returned. if
105
+     * not specified, all comments are returned.
106
+     * @param int $offset optional, starting point
107
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
108
+     * that may be returned
109
+     * @return IComment[]
110
+     * @since 9.0.0
111
+     */
112
+    public function getForObject(
113
+            $objectType,
114
+            $objectId,
115
+            $limit = 0,
116
+            $offset = 0,
117
+            \DateTime $notOlderThan = null
118
+    );
119 119
 
120
-	/**
121
-	 * @param $objectType string the object type, e.g. 'files'
122
-	 * @param $objectId string the id of the object
123
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
124
-	 * that may be returned
125
-	 * @return Int
126
-	 * @since 9.0.0
127
-	 */
128
-	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null);
120
+    /**
121
+     * @param $objectType string the object type, e.g. 'files'
122
+     * @param $objectId string the id of the object
123
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
124
+     * that may be returned
125
+     * @return Int
126
+     * @since 9.0.0
127
+     */
128
+    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null);
129 129
 
130
-	/**
131
-	 * Get the number of unread comments for all files in a folder
132
-	 *
133
-	 * @param int $folderId
134
-	 * @param IUser $user
135
-	 * @return array [$fileId => $unreadCount]
136
-	 * @since 12.0.0
137
-	 */
138
-	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user);
130
+    /**
131
+     * Get the number of unread comments for all files in a folder
132
+     *
133
+     * @param int $folderId
134
+     * @param IUser $user
135
+     * @return array [$fileId => $unreadCount]
136
+     * @since 12.0.0
137
+     */
138
+    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user);
139 139
 
140
-	/**
141
-	 * creates a new comment and returns it. At this point of time, it is not
142
-	 * saved in the used data storage. Use save() after setting other fields
143
-	 * of the comment (e.g. message or verb).
144
-	 *
145
-	 * @param string $actorType the actor type (e.g. 'users')
146
-	 * @param string $actorId a user id
147
-	 * @param string $objectType the object type the comment is attached to
148
-	 * @param string $objectId the object id the comment is attached to
149
-	 * @return IComment
150
-	 * @since 9.0.0
151
-	 */
152
-	public function create($actorType, $actorId, $objectType, $objectId);
140
+    /**
141
+     * creates a new comment and returns it. At this point of time, it is not
142
+     * saved in the used data storage. Use save() after setting other fields
143
+     * of the comment (e.g. message or verb).
144
+     *
145
+     * @param string $actorType the actor type (e.g. 'users')
146
+     * @param string $actorId a user id
147
+     * @param string $objectType the object type the comment is attached to
148
+     * @param string $objectId the object id the comment is attached to
149
+     * @return IComment
150
+     * @since 9.0.0
151
+     */
152
+    public function create($actorType, $actorId, $objectType, $objectId);
153 153
 
154
-	/**
155
-	 * permanently deletes the comment specified by the ID
156
-	 *
157
-	 * When the comment has child comments, their parent ID will be changed to
158
-	 * the parent ID of the item that is to be deleted.
159
-	 *
160
-	 * @param string $id
161
-	 * @return bool
162
-	 * @since 9.0.0
163
-	 */
164
-	public function delete($id);
154
+    /**
155
+     * permanently deletes the comment specified by the ID
156
+     *
157
+     * When the comment has child comments, their parent ID will be changed to
158
+     * the parent ID of the item that is to be deleted.
159
+     *
160
+     * @param string $id
161
+     * @return bool
162
+     * @since 9.0.0
163
+     */
164
+    public function delete($id);
165 165
 
166
-	/**
167
-	 * saves the comment permanently
168
-	 *
169
-	 * if the supplied comment has an empty ID, a new entry comment will be
170
-	 * saved and the instance updated with the new ID.
171
-	 *
172
-	 * Otherwise, an existing comment will be updated.
173
-	 *
174
-	 * Throws NotFoundException when a comment that is to be updated does not
175
-	 * exist anymore at this point of time.
176
-	 *
177
-	 * @param IComment $comment
178
-	 * @return bool
179
-	 * @throws NotFoundException
180
-	 * @since 9.0.0
181
-	 */
182
-	public function save(IComment $comment);
166
+    /**
167
+     * saves the comment permanently
168
+     *
169
+     * if the supplied comment has an empty ID, a new entry comment will be
170
+     * saved and the instance updated with the new ID.
171
+     *
172
+     * Otherwise, an existing comment will be updated.
173
+     *
174
+     * Throws NotFoundException when a comment that is to be updated does not
175
+     * exist anymore at this point of time.
176
+     *
177
+     * @param IComment $comment
178
+     * @return bool
179
+     * @throws NotFoundException
180
+     * @since 9.0.0
181
+     */
182
+    public function save(IComment $comment);
183 183
 
184
-	/**
185
-	 * removes references to specific actor (e.g. on user delete) of a comment.
186
-	 * The comment itself must not get lost/deleted.
187
-	 *
188
-	 * A 'users' type actor (type and id) should get replaced by the
189
-	 * value of the DELETED_USER constant of this interface.
190
-	 *
191
-	 * @param string $actorType the actor type (e.g. 'users')
192
-	 * @param string $actorId a user id
193
-	 * @return boolean
194
-	 * @since 9.0.0
195
-	 */
196
-	public function deleteReferencesOfActor($actorType, $actorId);
184
+    /**
185
+     * removes references to specific actor (e.g. on user delete) of a comment.
186
+     * The comment itself must not get lost/deleted.
187
+     *
188
+     * A 'users' type actor (type and id) should get replaced by the
189
+     * value of the DELETED_USER constant of this interface.
190
+     *
191
+     * @param string $actorType the actor type (e.g. 'users')
192
+     * @param string $actorId a user id
193
+     * @return boolean
194
+     * @since 9.0.0
195
+     */
196
+    public function deleteReferencesOfActor($actorType, $actorId);
197 197
 
198
-	/**
199
-	 * deletes all comments made of a specific object (e.g. on file delete)
200
-	 *
201
-	 * @param string $objectType the object type (e.g. 'files')
202
-	 * @param string $objectId e.g. the file id
203
-	 * @return boolean
204
-	 * @since 9.0.0
205
-	 */
206
-	public function deleteCommentsAtObject($objectType, $objectId);
198
+    /**
199
+     * deletes all comments made of a specific object (e.g. on file delete)
200
+     *
201
+     * @param string $objectType the object type (e.g. 'files')
202
+     * @param string $objectId e.g. the file id
203
+     * @return boolean
204
+     * @since 9.0.0
205
+     */
206
+    public function deleteCommentsAtObject($objectType, $objectId);
207 207
 
208
-	/**
209
-	 * sets the read marker for a given file to the specified date for the
210
-	 * provided user
211
-	 *
212
-	 * @param string $objectType
213
-	 * @param string $objectId
214
-	 * @param \DateTime $dateTime
215
-	 * @param \OCP\IUser $user
216
-	 * @since 9.0.0
217
-	 */
218
-	public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user);
208
+    /**
209
+     * sets the read marker for a given file to the specified date for the
210
+     * provided user
211
+     *
212
+     * @param string $objectType
213
+     * @param string $objectId
214
+     * @param \DateTime $dateTime
215
+     * @param \OCP\IUser $user
216
+     * @since 9.0.0
217
+     */
218
+    public function setReadMark($objectType, $objectId, \DateTime $dateTime, \OCP\IUser $user);
219 219
 
220
-	/**
221
-	 * returns the read marker for a given file to the specified date for the
222
-	 * provided user. It returns null, when the marker is not present, i.e.
223
-	 * no comments were marked as read.
224
-	 *
225
-	 * @param string $objectType
226
-	 * @param string $objectId
227
-	 * @param \OCP\IUser $user
228
-	 * @return \DateTime|null
229
-	 * @since 9.0.0
230
-	 */
231
-	public function getReadMark($objectType, $objectId, \OCP\IUser $user);
220
+    /**
221
+     * returns the read marker for a given file to the specified date for the
222
+     * provided user. It returns null, when the marker is not present, i.e.
223
+     * no comments were marked as read.
224
+     *
225
+     * @param string $objectType
226
+     * @param string $objectId
227
+     * @param \OCP\IUser $user
228
+     * @return \DateTime|null
229
+     * @since 9.0.0
230
+     */
231
+    public function getReadMark($objectType, $objectId, \OCP\IUser $user);
232 232
 
233
-	/**
234
-	 * deletes the read markers for the specified user
235
-	 *
236
-	 * @param \OCP\IUser $user
237
-	 * @return bool
238
-	 * @since 9.0.0
239
-	 */
240
-	public function deleteReadMarksFromUser(\OCP\IUser $user);
233
+    /**
234
+     * deletes the read markers for the specified user
235
+     *
236
+     * @param \OCP\IUser $user
237
+     * @return bool
238
+     * @since 9.0.0
239
+     */
240
+    public function deleteReadMarksFromUser(\OCP\IUser $user);
241 241
 
242
-	/**
243
-	 * deletes the read markers on the specified object
244
-	 *
245
-	 * @param string $objectType
246
-	 * @param string $objectId
247
-	 * @return bool
248
-	 * @since 9.0.0
249
-	 */
250
-	public function deleteReadMarksOnObject($objectType, $objectId);
242
+    /**
243
+     * deletes the read markers on the specified object
244
+     *
245
+     * @param string $objectType
246
+     * @param string $objectId
247
+     * @return bool
248
+     * @since 9.0.0
249
+     */
250
+    public function deleteReadMarksOnObject($objectType, $objectId);
251 251
 
252
-	/**
253
-	 * registers an Entity to the manager, so event notifications can be send
254
-	 * to consumers of the comments infrastructure
255
-	 *
256
-	 * @param \Closure $closure
257
-	 * @since 11.0.0
258
-	 */
259
-	public function registerEventHandler(\Closure $closure);
252
+    /**
253
+     * registers an Entity to the manager, so event notifications can be send
254
+     * to consumers of the comments infrastructure
255
+     *
256
+     * @param \Closure $closure
257
+     * @since 11.0.0
258
+     */
259
+    public function registerEventHandler(\Closure $closure);
260 260
 
261
-	/**
262
-	 * registers a method that resolves an ID to a display name for a given type
263
-	 *
264
-	 * @param string $type
265
-	 * @param \Closure $closure
266
-	 * @throws \OutOfBoundsException
267
-	 * @since 11.0.0
268
-	 *
269
-	 * Only one resolver shall be registered per type. Otherwise a
270
-	 * \OutOfBoundsException has to thrown.
271
-	 */
272
-	public function registerDisplayNameResolver($type, \Closure $closure);
261
+    /**
262
+     * registers a method that resolves an ID to a display name for a given type
263
+     *
264
+     * @param string $type
265
+     * @param \Closure $closure
266
+     * @throws \OutOfBoundsException
267
+     * @since 11.0.0
268
+     *
269
+     * Only one resolver shall be registered per type. Otherwise a
270
+     * \OutOfBoundsException has to thrown.
271
+     */
272
+    public function registerDisplayNameResolver($type, \Closure $closure);
273 273
 
274
-	/**
275
-	 * resolves a given ID of a given Type to a display name.
276
-	 *
277
-	 * @param string $type
278
-	 * @param string $id
279
-	 * @return string
280
-	 * @throws \OutOfBoundsException
281
-	 * @since 11.0.0
282
-	 *
283
-	 * If a provided type was not registered, an \OutOfBoundsException shall
284
-	 * be thrown. It is upon the resolver discretion what to return of the
285
-	 * provided ID is unknown. It must be ensured that a string is returned.
286
-	 */
287
-	public function resolveDisplayName($type, $id);
274
+    /**
275
+     * resolves a given ID of a given Type to a display name.
276
+     *
277
+     * @param string $type
278
+     * @param string $id
279
+     * @return string
280
+     * @throws \OutOfBoundsException
281
+     * @since 11.0.0
282
+     *
283
+     * If a provided type was not registered, an \OutOfBoundsException shall
284
+     * be thrown. It is upon the resolver discretion what to return of the
285
+     * provided ID is unknown. It must be ensured that a string is returned.
286
+     */
287
+    public function resolveDisplayName($type, $id);
288 288
 
289 289
 }
Please login to merge, or discard this patch.
lib/private/DB/QueryBuilder/QuoteHelper.php 2 patches
Indentation   +41 added lines, -41 removed lines patch added patch discarded remove patch
@@ -27,55 +27,55 @@
 block discarded – undo
27 27
 use OCP\DB\QueryBuilder\IQueryFunction;
28 28
 
29 29
 class QuoteHelper {
30
-	/**
31
-	 * @param array|string|ILiteral|IParameter|IQueryFunction $strings string, Literal or Parameter
32
-	 * @return array|string
33
-	 */
34
-	public function quoteColumnNames($strings) {
35
-		if (!is_array($strings)) {
36
-			return $this->quoteColumnName($strings);
37
-		}
30
+    /**
31
+     * @param array|string|ILiteral|IParameter|IQueryFunction $strings string, Literal or Parameter
32
+     * @return array|string
33
+     */
34
+    public function quoteColumnNames($strings) {
35
+        if (!is_array($strings)) {
36
+            return $this->quoteColumnName($strings);
37
+        }
38 38
 
39
-		$return = [];
40
-		foreach ($strings as $string) {
41
-			$return[] = $this->quoteColumnName($string);
42
-		}
39
+        $return = [];
40
+        foreach ($strings as $string) {
41
+            $return[] = $this->quoteColumnName($string);
42
+        }
43 43
 
44
-		return $return;
45
-	}
44
+        return $return;
45
+    }
46 46
 
47
-	/**
48
-	 * @param string|ILiteral|IParameter|IQueryFunction $string string, Literal or Parameter
49
-	 * @return string
50
-	 */
51
-	public function quoteColumnName($string) {
52
-		if ($string instanceof IParameter || $string instanceof ILiteral || $string instanceof IQueryFunction) {
53
-			return (string) $string;
54
-		}
47
+    /**
48
+     * @param string|ILiteral|IParameter|IQueryFunction $string string, Literal or Parameter
49
+     * @return string
50
+     */
51
+    public function quoteColumnName($string) {
52
+        if ($string instanceof IParameter || $string instanceof ILiteral || $string instanceof IQueryFunction) {
53
+            return (string) $string;
54
+        }
55 55
 
56
-		if ($string === null || $string === 'null' || $string === '*') {
57
-			return $string;
58
-		}
56
+        if ($string === null || $string === 'null' || $string === '*') {
57
+            return $string;
58
+        }
59 59
 
60
-		if (!is_string($string)) {
61
-			throw new \InvalidArgumentException('Only strings, Literals and Parameters are allowed');
62
-		}
60
+        if (!is_string($string)) {
61
+            throw new \InvalidArgumentException('Only strings, Literals and Parameters are allowed');
62
+        }
63 63
 
64
-		$string = str_replace(' AS ', ' as ', $string);
65
-		if (substr_count($string, ' as ')) {
66
-			return implode(' as ', array_map([$this, 'quoteColumnName'], explode(' as ', $string, 2)));
67
-		}
64
+        $string = str_replace(' AS ', ' as ', $string);
65
+        if (substr_count($string, ' as ')) {
66
+            return implode(' as ', array_map([$this, 'quoteColumnName'], explode(' as ', $string, 2)));
67
+        }
68 68
 
69
-		if (substr_count($string, '.')) {
70
-			list($alias, $columnName) = explode('.', $string, 2);
69
+        if (substr_count($string, '.')) {
70
+            list($alias, $columnName) = explode('.', $string, 2);
71 71
 
72
-			if ($columnName === '*') {
73
-				return $string;
74
-			}
72
+            if ($columnName === '*') {
73
+                return $string;
74
+            }
75 75
 
76
-			return '`' . $alias . '`.`' . $columnName . '`';
77
-		}
76
+            return '`' . $alias . '`.`' . $columnName . '`';
77
+        }
78 78
 
79
-		return '`' . $string . '`';
80
-	}
79
+        return '`' . $string . '`';
80
+    }
81 81
 }
Please login to merge, or discard this patch.
Spacing   +2 added lines, -2 removed lines patch added patch discarded remove patch
@@ -73,9 +73,9 @@
 block discarded – undo
73 73
 				return $string;
74 74
 			}
75 75
 
76
-			return '`' . $alias . '`.`' . $columnName . '`';
76
+			return '`'.$alias.'`.`'.$columnName.'`';
77 77
 		}
78 78
 
79
-		return '`' . $string . '`';
79
+		return '`'.$string.'`';
80 80
 	}
81 81
 }
Please login to merge, or discard this patch.
lib/private/Comments/Manager.php 2 patches
Indentation   +841 added lines, -841 removed lines patch added patch discarded remove patch
@@ -39,845 +39,845 @@
 block discarded – undo
39 39
 
40 40
 class Manager implements ICommentsManager {
41 41
 
42
-	/** @var  IDBConnection */
43
-	protected $dbConn;
44
-
45
-	/** @var  ILogger */
46
-	protected $logger;
47
-
48
-	/** @var IConfig */
49
-	protected $config;
50
-
51
-	/** @var IComment[] */
52
-	protected $commentsCache = [];
53
-
54
-	/** @var  \Closure[] */
55
-	protected $eventHandlerClosures = [];
56
-
57
-	/** @var  ICommentsEventHandler[] */
58
-	protected $eventHandlers = [];
59
-
60
-	/** @var \Closure[] */
61
-	protected $displayNameResolvers = [];
62
-
63
-	/**
64
-	 * Manager constructor.
65
-	 *
66
-	 * @param IDBConnection $dbConn
67
-	 * @param ILogger $logger
68
-	 * @param IConfig $config
69
-	 */
70
-	public function __construct(
71
-		IDBConnection $dbConn,
72
-		ILogger $logger,
73
-		IConfig $config
74
-	) {
75
-		$this->dbConn = $dbConn;
76
-		$this->logger = $logger;
77
-		$this->config = $config;
78
-	}
79
-
80
-	/**
81
-	 * converts data base data into PHP native, proper types as defined by
82
-	 * IComment interface.
83
-	 *
84
-	 * @param array $data
85
-	 * @return array
86
-	 */
87
-	protected function normalizeDatabaseData(array $data) {
88
-		$data['id'] = strval($data['id']);
89
-		$data['parent_id'] = strval($data['parent_id']);
90
-		$data['topmost_parent_id'] = strval($data['topmost_parent_id']);
91
-		$data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
92
-		if (!is_null($data['latest_child_timestamp'])) {
93
-			$data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
94
-		}
95
-		$data['children_count'] = intval($data['children_count']);
96
-		return $data;
97
-	}
98
-
99
-	/**
100
-	 * prepares a comment for an insert or update operation after making sure
101
-	 * all necessary fields have a value assigned.
102
-	 *
103
-	 * @param IComment $comment
104
-	 * @return IComment returns the same updated IComment instance as provided
105
-	 *                  by parameter for convenience
106
-	 * @throws \UnexpectedValueException
107
-	 */
108
-	protected function prepareCommentForDatabaseWrite(IComment $comment) {
109
-		if (!$comment->getActorType()
110
-			|| !$comment->getActorId()
111
-			|| !$comment->getObjectType()
112
-			|| !$comment->getObjectId()
113
-			|| !$comment->getVerb()
114
-		) {
115
-			throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
116
-		}
117
-
118
-		if ($comment->getId() === '') {
119
-			$comment->setChildrenCount(0);
120
-			$comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
121
-			$comment->setLatestChildDateTime(null);
122
-		}
123
-
124
-		if (is_null($comment->getCreationDateTime())) {
125
-			$comment->setCreationDateTime(new \DateTime());
126
-		}
127
-
128
-		if ($comment->getParentId() !== '0') {
129
-			$comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
130
-		} else {
131
-			$comment->setTopmostParentId('0');
132
-		}
133
-
134
-		$this->cache($comment);
135
-
136
-		return $comment;
137
-	}
138
-
139
-	/**
140
-	 * returns the topmost parent id of a given comment identified by ID
141
-	 *
142
-	 * @param string $id
143
-	 * @return string
144
-	 * @throws NotFoundException
145
-	 */
146
-	protected function determineTopmostParentId($id) {
147
-		$comment = $this->get($id);
148
-		if ($comment->getParentId() === '0') {
149
-			return $comment->getId();
150
-		} else {
151
-			return $this->determineTopmostParentId($comment->getId());
152
-		}
153
-	}
154
-
155
-	/**
156
-	 * updates child information of a comment
157
-	 *
158
-	 * @param string $id
159
-	 * @param \DateTime $cDateTime the date time of the most recent child
160
-	 * @throws NotFoundException
161
-	 */
162
-	protected function updateChildrenInformation($id, \DateTime $cDateTime) {
163
-		$qb = $this->dbConn->getQueryBuilder();
164
-		$query = $qb->select($qb->createFunction('COUNT(`id`)'))
165
-			->from('comments')
166
-			->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
167
-			->setParameter('id', $id);
168
-
169
-		$resultStatement = $query->execute();
170
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
171
-		$resultStatement->closeCursor();
172
-		$children = intval($data[0]);
173
-
174
-		$comment = $this->get($id);
175
-		$comment->setChildrenCount($children);
176
-		$comment->setLatestChildDateTime($cDateTime);
177
-		$this->save($comment);
178
-	}
179
-
180
-	/**
181
-	 * Tests whether actor or object type and id parameters are acceptable.
182
-	 * Throws exception if not.
183
-	 *
184
-	 * @param string $role
185
-	 * @param string $type
186
-	 * @param string $id
187
-	 * @throws \InvalidArgumentException
188
-	 */
189
-	protected function checkRoleParameters($role, $type, $id) {
190
-		if (
191
-			!is_string($type) || empty($type)
192
-			|| !is_string($id) || empty($id)
193
-		) {
194
-			throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
195
-		}
196
-	}
197
-
198
-	/**
199
-	 * run-time caches a comment
200
-	 *
201
-	 * @param IComment $comment
202
-	 */
203
-	protected function cache(IComment $comment) {
204
-		$id = $comment->getId();
205
-		if (empty($id)) {
206
-			return;
207
-		}
208
-		$this->commentsCache[strval($id)] = $comment;
209
-	}
210
-
211
-	/**
212
-	 * removes an entry from the comments run time cache
213
-	 *
214
-	 * @param mixed $id the comment's id
215
-	 */
216
-	protected function uncache($id) {
217
-		$id = strval($id);
218
-		if (isset($this->commentsCache[$id])) {
219
-			unset($this->commentsCache[$id]);
220
-		}
221
-	}
222
-
223
-	/**
224
-	 * returns a comment instance
225
-	 *
226
-	 * @param string $id the ID of the comment
227
-	 * @return IComment
228
-	 * @throws NotFoundException
229
-	 * @throws \InvalidArgumentException
230
-	 * @since 9.0.0
231
-	 */
232
-	public function get($id) {
233
-		if (intval($id) === 0) {
234
-			throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
235
-		}
236
-
237
-		if (isset($this->commentsCache[$id])) {
238
-			return $this->commentsCache[$id];
239
-		}
240
-
241
-		$qb = $this->dbConn->getQueryBuilder();
242
-		$resultStatement = $qb->select('*')
243
-			->from('comments')
244
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
245
-			->setParameter('id', $id, IQueryBuilder::PARAM_INT)
246
-			->execute();
247
-
248
-		$data = $resultStatement->fetch();
249
-		$resultStatement->closeCursor();
250
-		if (!$data) {
251
-			throw new NotFoundException();
252
-		}
253
-
254
-		$comment = new Comment($this->normalizeDatabaseData($data));
255
-		$this->cache($comment);
256
-		return $comment;
257
-	}
258
-
259
-	/**
260
-	 * returns the comment specified by the id and all it's child comments.
261
-	 * At this point of time, we do only support one level depth.
262
-	 *
263
-	 * @param string $id
264
-	 * @param int $limit max number of entries to return, 0 returns all
265
-	 * @param int $offset the start entry
266
-	 * @return array
267
-	 * @since 9.0.0
268
-	 *
269
-	 * The return array looks like this
270
-	 * [
271
-	 *   'comment' => IComment, // root comment
272
-	 *   'replies' =>
273
-	 *   [
274
-	 *     0 =>
275
-	 *     [
276
-	 *       'comment' => IComment,
277
-	 *       'replies' => []
278
-	 *     ]
279
-	 *     1 =>
280
-	 *     [
281
-	 *       'comment' => IComment,
282
-	 *       'replies'=> []
283
-	 *     ],
284
-	 *     …
285
-	 *   ]
286
-	 * ]
287
-	 */
288
-	public function getTree($id, $limit = 0, $offset = 0) {
289
-		$tree = [];
290
-		$tree['comment'] = $this->get($id);
291
-		$tree['replies'] = [];
292
-
293
-		$qb = $this->dbConn->getQueryBuilder();
294
-		$query = $qb->select('*')
295
-			->from('comments')
296
-			->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
297
-			->orderBy('creation_timestamp', 'DESC')
298
-			->setParameter('id', $id);
299
-
300
-		if ($limit > 0) {
301
-			$query->setMaxResults($limit);
302
-		}
303
-		if ($offset > 0) {
304
-			$query->setFirstResult($offset);
305
-		}
306
-
307
-		$resultStatement = $query->execute();
308
-		while ($data = $resultStatement->fetch()) {
309
-			$comment = new Comment($this->normalizeDatabaseData($data));
310
-			$this->cache($comment);
311
-			$tree['replies'][] = [
312
-				'comment' => $comment,
313
-				'replies' => []
314
-			];
315
-		}
316
-		$resultStatement->closeCursor();
317
-
318
-		return $tree;
319
-	}
320
-
321
-	/**
322
-	 * returns comments for a specific object (e.g. a file).
323
-	 *
324
-	 * The sort order is always newest to oldest.
325
-	 *
326
-	 * @param string $objectType the object type, e.g. 'files'
327
-	 * @param string $objectId the id of the object
328
-	 * @param int $limit optional, number of maximum comments to be returned. if
329
-	 * not specified, all comments are returned.
330
-	 * @param int $offset optional, starting point
331
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
332
-	 * that may be returned
333
-	 * @return IComment[]
334
-	 * @since 9.0.0
335
-	 */
336
-	public function getForObject(
337
-		$objectType,
338
-		$objectId,
339
-		$limit = 0,
340
-		$offset = 0,
341
-		\DateTime $notOlderThan = null
342
-	) {
343
-		$comments = [];
344
-
345
-		$qb = $this->dbConn->getQueryBuilder();
346
-		$query = $qb->select('*')
347
-			->from('comments')
348
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
349
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
350
-			->orderBy('creation_timestamp', 'DESC')
351
-			->setParameter('type', $objectType)
352
-			->setParameter('id', $objectId);
353
-
354
-		if ($limit > 0) {
355
-			$query->setMaxResults($limit);
356
-		}
357
-		if ($offset > 0) {
358
-			$query->setFirstResult($offset);
359
-		}
360
-		if (!is_null($notOlderThan)) {
361
-			$query
362
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
363
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
364
-		}
365
-
366
-		$resultStatement = $query->execute();
367
-		while ($data = $resultStatement->fetch()) {
368
-			$comment = new Comment($this->normalizeDatabaseData($data));
369
-			$this->cache($comment);
370
-			$comments[] = $comment;
371
-		}
372
-		$resultStatement->closeCursor();
373
-
374
-		return $comments;
375
-	}
376
-
377
-	/**
378
-	 * @param $objectType string the object type, e.g. 'files'
379
-	 * @param $objectId string the id of the object
380
-	 * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
381
-	 * that may be returned
382
-	 * @return Int
383
-	 * @since 9.0.0
384
-	 */
385
-	public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) {
386
-		$qb = $this->dbConn->getQueryBuilder();
387
-		$query = $qb->select($qb->createFunction('COUNT(`id`)'))
388
-			->from('comments')
389
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
390
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
391
-			->setParameter('type', $objectType)
392
-			->setParameter('id', $objectId);
393
-
394
-		if (!is_null($notOlderThan)) {
395
-			$query
396
-				->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
397
-				->setParameter('notOlderThan', $notOlderThan, 'datetime');
398
-		}
399
-
400
-		$resultStatement = $query->execute();
401
-		$data = $resultStatement->fetch(\PDO::FETCH_NUM);
402
-		$resultStatement->closeCursor();
403
-		return intval($data[0]);
404
-	}
405
-
406
-	/**
407
-	 * Get the number of unread comments for all files in a folder
408
-	 *
409
-	 * @param int $folderId
410
-	 * @param IUser $user
411
-	 * @return array [$fileId => $unreadCount]
412
-	 */
413
-	public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
414
-		$qb = $this->dbConn->getQueryBuilder();
415
-		$castAs = ($this->dbConn->getDatabasePlatform() instanceof MySqlPlatform) ? 'unsigned integer' : 'int';
416
-		$query = $qb->select('fileid', $qb->createFunction(
417
-			'COUNT(' . $qb->getColumnName('c.id') . ')')
418
-		)->from('comments', 'c')
419
-			->innerJoin('c', 'filecache', 'f', $qb->expr()->andX(
420
-				$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
421
-				$qb->expr()->eq('f.fileid', $qb->createFunction(
422
-					'cast(' . $qb->getColumnName('c.object_id') . ' as ' . $castAs . ')'
423
-				))
424
-			))
425
-			->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
426
-				$qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
427
-				$qb->expr()->eq('m.object_id', 'c.object_id'),
428
-				$qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID()))
429
-			))
430
-			->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)))
431
-			->andWhere($qb->expr()->orX(
432
-				$qb->expr()->gt('c.creation_timestamp', 'marker_datetime'),
433
-				$qb->expr()->isNull('marker_datetime')
434
-			))
435
-			->groupBy('f.fileid');
436
-
437
-		$resultStatement = $query->execute();
438
-		return array_map(function ($count) {
439
-			return (int)$count;
440
-		}, $resultStatement->fetchAll(\PDO::FETCH_KEY_PAIR));
441
-	}
442
-
443
-	/**
444
-	 * creates a new comment and returns it. At this point of time, it is not
445
-	 * saved in the used data storage. Use save() after setting other fields
446
-	 * of the comment (e.g. message or verb).
447
-	 *
448
-	 * @param string $actorType the actor type (e.g. 'users')
449
-	 * @param string $actorId a user id
450
-	 * @param string $objectType the object type the comment is attached to
451
-	 * @param string $objectId the object id the comment is attached to
452
-	 * @return IComment
453
-	 * @since 9.0.0
454
-	 */
455
-	public function create($actorType, $actorId, $objectType, $objectId) {
456
-		$comment = new Comment();
457
-		$comment
458
-			->setActor($actorType, $actorId)
459
-			->setObject($objectType, $objectId);
460
-		return $comment;
461
-	}
462
-
463
-	/**
464
-	 * permanently deletes the comment specified by the ID
465
-	 *
466
-	 * When the comment has child comments, their parent ID will be changed to
467
-	 * the parent ID of the item that is to be deleted.
468
-	 *
469
-	 * @param string $id
470
-	 * @return bool
471
-	 * @throws \InvalidArgumentException
472
-	 * @since 9.0.0
473
-	 */
474
-	public function delete($id) {
475
-		if (!is_string($id)) {
476
-			throw new \InvalidArgumentException('Parameter must be string');
477
-		}
478
-
479
-		try {
480
-			$comment = $this->get($id);
481
-		} catch (\Exception $e) {
482
-			// Ignore exceptions, we just don't fire a hook then
483
-			$comment = null;
484
-		}
485
-
486
-		$qb = $this->dbConn->getQueryBuilder();
487
-		$query = $qb->delete('comments')
488
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
489
-			->setParameter('id', $id);
490
-
491
-		try {
492
-			$affectedRows = $query->execute();
493
-			$this->uncache($id);
494
-		} catch (DriverException $e) {
495
-			$this->logger->logException($e, ['app' => 'core_comments']);
496
-			return false;
497
-		}
498
-
499
-		if ($affectedRows > 0 && $comment instanceof IComment) {
500
-			$this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
501
-		}
502
-
503
-		return ($affectedRows > 0);
504
-	}
505
-
506
-	/**
507
-	 * saves the comment permanently
508
-	 *
509
-	 * if the supplied comment has an empty ID, a new entry comment will be
510
-	 * saved and the instance updated with the new ID.
511
-	 *
512
-	 * Otherwise, an existing comment will be updated.
513
-	 *
514
-	 * Throws NotFoundException when a comment that is to be updated does not
515
-	 * exist anymore at this point of time.
516
-	 *
517
-	 * @param IComment $comment
518
-	 * @return bool
519
-	 * @throws NotFoundException
520
-	 * @since 9.0.0
521
-	 */
522
-	public function save(IComment $comment) {
523
-		if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
524
-			$result = $this->insert($comment);
525
-		} else {
526
-			$result = $this->update($comment);
527
-		}
528
-
529
-		if ($result && !!$comment->getParentId()) {
530
-			$this->updateChildrenInformation(
531
-				$comment->getParentId(),
532
-				$comment->getCreationDateTime()
533
-			);
534
-			$this->cache($comment);
535
-		}
536
-
537
-		return $result;
538
-	}
539
-
540
-	/**
541
-	 * inserts the provided comment in the database
542
-	 *
543
-	 * @param IComment $comment
544
-	 * @return bool
545
-	 */
546
-	protected function insert(IComment &$comment) {
547
-		$qb = $this->dbConn->getQueryBuilder();
548
-		$affectedRows = $qb
549
-			->insert('comments')
550
-			->values([
551
-				'parent_id' => $qb->createNamedParameter($comment->getParentId()),
552
-				'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
553
-				'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
554
-				'actor_type' => $qb->createNamedParameter($comment->getActorType()),
555
-				'actor_id' => $qb->createNamedParameter($comment->getActorId()),
556
-				'message' => $qb->createNamedParameter($comment->getMessage()),
557
-				'verb' => $qb->createNamedParameter($comment->getVerb()),
558
-				'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
559
-				'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
560
-				'object_type' => $qb->createNamedParameter($comment->getObjectType()),
561
-				'object_id' => $qb->createNamedParameter($comment->getObjectId()),
562
-			])
563
-			->execute();
564
-
565
-		if ($affectedRows > 0) {
566
-			$comment->setId(strval($qb->getLastInsertId()));
567
-			$this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
568
-		}
569
-
570
-		return $affectedRows > 0;
571
-	}
572
-
573
-	/**
574
-	 * updates a Comment data row
575
-	 *
576
-	 * @param IComment $comment
577
-	 * @return bool
578
-	 * @throws NotFoundException
579
-	 */
580
-	protected function update(IComment $comment) {
581
-		// for properly working preUpdate Events we need the old comments as is
582
-		// in the DB and overcome caching. Also avoid that outdated information stays.
583
-		$this->uncache($comment->getId());
584
-		$this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
585
-		$this->uncache($comment->getId());
586
-
587
-		$qb = $this->dbConn->getQueryBuilder();
588
-		$affectedRows = $qb
589
-			->update('comments')
590
-			->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
591
-			->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
592
-			->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
593
-			->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
594
-			->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
595
-			->set('message', $qb->createNamedParameter($comment->getMessage()))
596
-			->set('verb', $qb->createNamedParameter($comment->getVerb()))
597
-			->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
598
-			->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
599
-			->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
600
-			->set('object_id', $qb->createNamedParameter($comment->getObjectId()))
601
-			->where($qb->expr()->eq('id', $qb->createParameter('id')))
602
-			->setParameter('id', $comment->getId())
603
-			->execute();
604
-
605
-		if ($affectedRows === 0) {
606
-			throw new NotFoundException('Comment to update does ceased to exist');
607
-		}
608
-
609
-		$this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
610
-
611
-		return $affectedRows > 0;
612
-	}
613
-
614
-	/**
615
-	 * removes references to specific actor (e.g. on user delete) of a comment.
616
-	 * The comment itself must not get lost/deleted.
617
-	 *
618
-	 * @param string $actorType the actor type (e.g. 'users')
619
-	 * @param string $actorId a user id
620
-	 * @return boolean
621
-	 * @since 9.0.0
622
-	 */
623
-	public function deleteReferencesOfActor($actorType, $actorId) {
624
-		$this->checkRoleParameters('Actor', $actorType, $actorId);
625
-
626
-		$qb = $this->dbConn->getQueryBuilder();
627
-		$affectedRows = $qb
628
-			->update('comments')
629
-			->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
630
-			->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
631
-			->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
632
-			->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
633
-			->setParameter('type', $actorType)
634
-			->setParameter('id', $actorId)
635
-			->execute();
636
-
637
-		$this->commentsCache = [];
638
-
639
-		return is_int($affectedRows);
640
-	}
641
-
642
-	/**
643
-	 * deletes all comments made of a specific object (e.g. on file delete)
644
-	 *
645
-	 * @param string $objectType the object type (e.g. 'files')
646
-	 * @param string $objectId e.g. the file id
647
-	 * @return boolean
648
-	 * @since 9.0.0
649
-	 */
650
-	public function deleteCommentsAtObject($objectType, $objectId) {
651
-		$this->checkRoleParameters('Object', $objectType, $objectId);
652
-
653
-		$qb = $this->dbConn->getQueryBuilder();
654
-		$affectedRows = $qb
655
-			->delete('comments')
656
-			->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
657
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
658
-			->setParameter('type', $objectType)
659
-			->setParameter('id', $objectId)
660
-			->execute();
661
-
662
-		$this->commentsCache = [];
663
-
664
-		return is_int($affectedRows);
665
-	}
666
-
667
-	/**
668
-	 * deletes the read markers for the specified user
669
-	 *
670
-	 * @param \OCP\IUser $user
671
-	 * @return bool
672
-	 * @since 9.0.0
673
-	 */
674
-	public function deleteReadMarksFromUser(IUser $user) {
675
-		$qb = $this->dbConn->getQueryBuilder();
676
-		$query = $qb->delete('comments_read_markers')
677
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
678
-			->setParameter('user_id', $user->getUID());
679
-
680
-		try {
681
-			$affectedRows = $query->execute();
682
-		} catch (DriverException $e) {
683
-			$this->logger->logException($e, ['app' => 'core_comments']);
684
-			return false;
685
-		}
686
-		return ($affectedRows > 0);
687
-	}
688
-
689
-	/**
690
-	 * sets the read marker for a given file to the specified date for the
691
-	 * provided user
692
-	 *
693
-	 * @param string $objectType
694
-	 * @param string $objectId
695
-	 * @param \DateTime $dateTime
696
-	 * @param IUser $user
697
-	 * @since 9.0.0
698
-	 */
699
-	public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
700
-		$this->checkRoleParameters('Object', $objectType, $objectId);
701
-
702
-		$qb = $this->dbConn->getQueryBuilder();
703
-		$values = [
704
-			'user_id' => $qb->createNamedParameter($user->getUID()),
705
-			'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
706
-			'object_type' => $qb->createNamedParameter($objectType),
707
-			'object_id' => $qb->createNamedParameter($objectId),
708
-		];
709
-
710
-		// Strategy: try to update, if this does not return affected rows, do an insert.
711
-		$affectedRows = $qb
712
-			->update('comments_read_markers')
713
-			->set('user_id', $values['user_id'])
714
-			->set('marker_datetime', $values['marker_datetime'])
715
-			->set('object_type', $values['object_type'])
716
-			->set('object_id', $values['object_id'])
717
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
718
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
719
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
720
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
721
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
722
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
723
-			->execute();
724
-
725
-		if ($affectedRows > 0) {
726
-			return;
727
-		}
728
-
729
-		$qb->insert('comments_read_markers')
730
-			->values($values)
731
-			->execute();
732
-	}
733
-
734
-	/**
735
-	 * returns the read marker for a given file to the specified date for the
736
-	 * provided user. It returns null, when the marker is not present, i.e.
737
-	 * no comments were marked as read.
738
-	 *
739
-	 * @param string $objectType
740
-	 * @param string $objectId
741
-	 * @param IUser $user
742
-	 * @return \DateTime|null
743
-	 * @since 9.0.0
744
-	 */
745
-	public function getReadMark($objectType, $objectId, IUser $user) {
746
-		$qb = $this->dbConn->getQueryBuilder();
747
-		$resultStatement = $qb->select('marker_datetime')
748
-			->from('comments_read_markers')
749
-			->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
750
-			->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
751
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
752
-			->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
753
-			->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
754
-			->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
755
-			->execute();
756
-
757
-		$data = $resultStatement->fetch();
758
-		$resultStatement->closeCursor();
759
-		if (!$data || is_null($data['marker_datetime'])) {
760
-			return null;
761
-		}
762
-
763
-		return new \DateTime($data['marker_datetime']);
764
-	}
765
-
766
-	/**
767
-	 * deletes the read markers on the specified object
768
-	 *
769
-	 * @param string $objectType
770
-	 * @param string $objectId
771
-	 * @return bool
772
-	 * @since 9.0.0
773
-	 */
774
-	public function deleteReadMarksOnObject($objectType, $objectId) {
775
-		$this->checkRoleParameters('Object', $objectType, $objectId);
776
-
777
-		$qb = $this->dbConn->getQueryBuilder();
778
-		$query = $qb->delete('comments_read_markers')
779
-			->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
780
-			->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
781
-			->setParameter('object_type', $objectType)
782
-			->setParameter('object_id', $objectId);
783
-
784
-		try {
785
-			$affectedRows = $query->execute();
786
-		} catch (DriverException $e) {
787
-			$this->logger->logException($e, ['app' => 'core_comments']);
788
-			return false;
789
-		}
790
-		return ($affectedRows > 0);
791
-	}
792
-
793
-	/**
794
-	 * registers an Entity to the manager, so event notifications can be send
795
-	 * to consumers of the comments infrastructure
796
-	 *
797
-	 * @param \Closure $closure
798
-	 */
799
-	public function registerEventHandler(\Closure $closure) {
800
-		$this->eventHandlerClosures[] = $closure;
801
-		$this->eventHandlers = [];
802
-	}
803
-
804
-	/**
805
-	 * registers a method that resolves an ID to a display name for a given type
806
-	 *
807
-	 * @param string $type
808
-	 * @param \Closure $closure
809
-	 * @throws \OutOfBoundsException
810
-	 * @since 11.0.0
811
-	 *
812
-	 * Only one resolver shall be registered per type. Otherwise a
813
-	 * \OutOfBoundsException has to thrown.
814
-	 */
815
-	public function registerDisplayNameResolver($type, \Closure $closure) {
816
-		if (!is_string($type)) {
817
-			throw new \InvalidArgumentException('String expected.');
818
-		}
819
-		if (isset($this->displayNameResolvers[$type])) {
820
-			throw new \OutOfBoundsException('Displayname resolver for this type already registered');
821
-		}
822
-		$this->displayNameResolvers[$type] = $closure;
823
-	}
824
-
825
-	/**
826
-	 * resolves a given ID of a given Type to a display name.
827
-	 *
828
-	 * @param string $type
829
-	 * @param string $id
830
-	 * @return string
831
-	 * @throws \OutOfBoundsException
832
-	 * @since 11.0.0
833
-	 *
834
-	 * If a provided type was not registered, an \OutOfBoundsException shall
835
-	 * be thrown. It is upon the resolver discretion what to return of the
836
-	 * provided ID is unknown. It must be ensured that a string is returned.
837
-	 */
838
-	public function resolveDisplayName($type, $id) {
839
-		if (!is_string($type)) {
840
-			throw new \InvalidArgumentException('String expected.');
841
-		}
842
-		if (!isset($this->displayNameResolvers[$type])) {
843
-			throw new \OutOfBoundsException('No Displayname resolver for this type registered');
844
-		}
845
-		return (string)$this->displayNameResolvers[$type]($id);
846
-	}
847
-
848
-	/**
849
-	 * returns valid, registered entities
850
-	 *
851
-	 * @return \OCP\Comments\ICommentsEventHandler[]
852
-	 */
853
-	private function getEventHandlers() {
854
-		if (!empty($this->eventHandlers)) {
855
-			return $this->eventHandlers;
856
-		}
857
-
858
-		$this->eventHandlers = [];
859
-		foreach ($this->eventHandlerClosures as $name => $closure) {
860
-			$entity = $closure();
861
-			if (!($entity instanceof ICommentsEventHandler)) {
862
-				throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
863
-			}
864
-			$this->eventHandlers[$name] = $entity;
865
-		}
866
-
867
-		return $this->eventHandlers;
868
-	}
869
-
870
-	/**
871
-	 * sends notifications to the registered entities
872
-	 *
873
-	 * @param $eventType
874
-	 * @param IComment $comment
875
-	 */
876
-	private function sendEvent($eventType, IComment $comment) {
877
-		$entities = $this->getEventHandlers();
878
-		$event = new CommentsEvent($eventType, $comment);
879
-		foreach ($entities as $entity) {
880
-			$entity->handle($event);
881
-		}
882
-	}
42
+    /** @var  IDBConnection */
43
+    protected $dbConn;
44
+
45
+    /** @var  ILogger */
46
+    protected $logger;
47
+
48
+    /** @var IConfig */
49
+    protected $config;
50
+
51
+    /** @var IComment[] */
52
+    protected $commentsCache = [];
53
+
54
+    /** @var  \Closure[] */
55
+    protected $eventHandlerClosures = [];
56
+
57
+    /** @var  ICommentsEventHandler[] */
58
+    protected $eventHandlers = [];
59
+
60
+    /** @var \Closure[] */
61
+    protected $displayNameResolvers = [];
62
+
63
+    /**
64
+     * Manager constructor.
65
+     *
66
+     * @param IDBConnection $dbConn
67
+     * @param ILogger $logger
68
+     * @param IConfig $config
69
+     */
70
+    public function __construct(
71
+        IDBConnection $dbConn,
72
+        ILogger $logger,
73
+        IConfig $config
74
+    ) {
75
+        $this->dbConn = $dbConn;
76
+        $this->logger = $logger;
77
+        $this->config = $config;
78
+    }
79
+
80
+    /**
81
+     * converts data base data into PHP native, proper types as defined by
82
+     * IComment interface.
83
+     *
84
+     * @param array $data
85
+     * @return array
86
+     */
87
+    protected function normalizeDatabaseData(array $data) {
88
+        $data['id'] = strval($data['id']);
89
+        $data['parent_id'] = strval($data['parent_id']);
90
+        $data['topmost_parent_id'] = strval($data['topmost_parent_id']);
91
+        $data['creation_timestamp'] = new \DateTime($data['creation_timestamp']);
92
+        if (!is_null($data['latest_child_timestamp'])) {
93
+            $data['latest_child_timestamp'] = new \DateTime($data['latest_child_timestamp']);
94
+        }
95
+        $data['children_count'] = intval($data['children_count']);
96
+        return $data;
97
+    }
98
+
99
+    /**
100
+     * prepares a comment for an insert or update operation after making sure
101
+     * all necessary fields have a value assigned.
102
+     *
103
+     * @param IComment $comment
104
+     * @return IComment returns the same updated IComment instance as provided
105
+     *                  by parameter for convenience
106
+     * @throws \UnexpectedValueException
107
+     */
108
+    protected function prepareCommentForDatabaseWrite(IComment $comment) {
109
+        if (!$comment->getActorType()
110
+            || !$comment->getActorId()
111
+            || !$comment->getObjectType()
112
+            || !$comment->getObjectId()
113
+            || !$comment->getVerb()
114
+        ) {
115
+            throw new \UnexpectedValueException('Actor, Object and Verb information must be provided for saving');
116
+        }
117
+
118
+        if ($comment->getId() === '') {
119
+            $comment->setChildrenCount(0);
120
+            $comment->setLatestChildDateTime(new \DateTime('0000-00-00 00:00:00', new \DateTimeZone('UTC')));
121
+            $comment->setLatestChildDateTime(null);
122
+        }
123
+
124
+        if (is_null($comment->getCreationDateTime())) {
125
+            $comment->setCreationDateTime(new \DateTime());
126
+        }
127
+
128
+        if ($comment->getParentId() !== '0') {
129
+            $comment->setTopmostParentId($this->determineTopmostParentId($comment->getParentId()));
130
+        } else {
131
+            $comment->setTopmostParentId('0');
132
+        }
133
+
134
+        $this->cache($comment);
135
+
136
+        return $comment;
137
+    }
138
+
139
+    /**
140
+     * returns the topmost parent id of a given comment identified by ID
141
+     *
142
+     * @param string $id
143
+     * @return string
144
+     * @throws NotFoundException
145
+     */
146
+    protected function determineTopmostParentId($id) {
147
+        $comment = $this->get($id);
148
+        if ($comment->getParentId() === '0') {
149
+            return $comment->getId();
150
+        } else {
151
+            return $this->determineTopmostParentId($comment->getId());
152
+        }
153
+    }
154
+
155
+    /**
156
+     * updates child information of a comment
157
+     *
158
+     * @param string $id
159
+     * @param \DateTime $cDateTime the date time of the most recent child
160
+     * @throws NotFoundException
161
+     */
162
+    protected function updateChildrenInformation($id, \DateTime $cDateTime) {
163
+        $qb = $this->dbConn->getQueryBuilder();
164
+        $query = $qb->select($qb->createFunction('COUNT(`id`)'))
165
+            ->from('comments')
166
+            ->where($qb->expr()->eq('parent_id', $qb->createParameter('id')))
167
+            ->setParameter('id', $id);
168
+
169
+        $resultStatement = $query->execute();
170
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
171
+        $resultStatement->closeCursor();
172
+        $children = intval($data[0]);
173
+
174
+        $comment = $this->get($id);
175
+        $comment->setChildrenCount($children);
176
+        $comment->setLatestChildDateTime($cDateTime);
177
+        $this->save($comment);
178
+    }
179
+
180
+    /**
181
+     * Tests whether actor or object type and id parameters are acceptable.
182
+     * Throws exception if not.
183
+     *
184
+     * @param string $role
185
+     * @param string $type
186
+     * @param string $id
187
+     * @throws \InvalidArgumentException
188
+     */
189
+    protected function checkRoleParameters($role, $type, $id) {
190
+        if (
191
+            !is_string($type) || empty($type)
192
+            || !is_string($id) || empty($id)
193
+        ) {
194
+            throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
195
+        }
196
+    }
197
+
198
+    /**
199
+     * run-time caches a comment
200
+     *
201
+     * @param IComment $comment
202
+     */
203
+    protected function cache(IComment $comment) {
204
+        $id = $comment->getId();
205
+        if (empty($id)) {
206
+            return;
207
+        }
208
+        $this->commentsCache[strval($id)] = $comment;
209
+    }
210
+
211
+    /**
212
+     * removes an entry from the comments run time cache
213
+     *
214
+     * @param mixed $id the comment's id
215
+     */
216
+    protected function uncache($id) {
217
+        $id = strval($id);
218
+        if (isset($this->commentsCache[$id])) {
219
+            unset($this->commentsCache[$id]);
220
+        }
221
+    }
222
+
223
+    /**
224
+     * returns a comment instance
225
+     *
226
+     * @param string $id the ID of the comment
227
+     * @return IComment
228
+     * @throws NotFoundException
229
+     * @throws \InvalidArgumentException
230
+     * @since 9.0.0
231
+     */
232
+    public function get($id) {
233
+        if (intval($id) === 0) {
234
+            throw new \InvalidArgumentException('IDs must be translatable to a number in this implementation.');
235
+        }
236
+
237
+        if (isset($this->commentsCache[$id])) {
238
+            return $this->commentsCache[$id];
239
+        }
240
+
241
+        $qb = $this->dbConn->getQueryBuilder();
242
+        $resultStatement = $qb->select('*')
243
+            ->from('comments')
244
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
245
+            ->setParameter('id', $id, IQueryBuilder::PARAM_INT)
246
+            ->execute();
247
+
248
+        $data = $resultStatement->fetch();
249
+        $resultStatement->closeCursor();
250
+        if (!$data) {
251
+            throw new NotFoundException();
252
+        }
253
+
254
+        $comment = new Comment($this->normalizeDatabaseData($data));
255
+        $this->cache($comment);
256
+        return $comment;
257
+    }
258
+
259
+    /**
260
+     * returns the comment specified by the id and all it's child comments.
261
+     * At this point of time, we do only support one level depth.
262
+     *
263
+     * @param string $id
264
+     * @param int $limit max number of entries to return, 0 returns all
265
+     * @param int $offset the start entry
266
+     * @return array
267
+     * @since 9.0.0
268
+     *
269
+     * The return array looks like this
270
+     * [
271
+     *   'comment' => IComment, // root comment
272
+     *   'replies' =>
273
+     *   [
274
+     *     0 =>
275
+     *     [
276
+     *       'comment' => IComment,
277
+     *       'replies' => []
278
+     *     ]
279
+     *     1 =>
280
+     *     [
281
+     *       'comment' => IComment,
282
+     *       'replies'=> []
283
+     *     ],
284
+     *     …
285
+     *   ]
286
+     * ]
287
+     */
288
+    public function getTree($id, $limit = 0, $offset = 0) {
289
+        $tree = [];
290
+        $tree['comment'] = $this->get($id);
291
+        $tree['replies'] = [];
292
+
293
+        $qb = $this->dbConn->getQueryBuilder();
294
+        $query = $qb->select('*')
295
+            ->from('comments')
296
+            ->where($qb->expr()->eq('topmost_parent_id', $qb->createParameter('id')))
297
+            ->orderBy('creation_timestamp', 'DESC')
298
+            ->setParameter('id', $id);
299
+
300
+        if ($limit > 0) {
301
+            $query->setMaxResults($limit);
302
+        }
303
+        if ($offset > 0) {
304
+            $query->setFirstResult($offset);
305
+        }
306
+
307
+        $resultStatement = $query->execute();
308
+        while ($data = $resultStatement->fetch()) {
309
+            $comment = new Comment($this->normalizeDatabaseData($data));
310
+            $this->cache($comment);
311
+            $tree['replies'][] = [
312
+                'comment' => $comment,
313
+                'replies' => []
314
+            ];
315
+        }
316
+        $resultStatement->closeCursor();
317
+
318
+        return $tree;
319
+    }
320
+
321
+    /**
322
+     * returns comments for a specific object (e.g. a file).
323
+     *
324
+     * The sort order is always newest to oldest.
325
+     *
326
+     * @param string $objectType the object type, e.g. 'files'
327
+     * @param string $objectId the id of the object
328
+     * @param int $limit optional, number of maximum comments to be returned. if
329
+     * not specified, all comments are returned.
330
+     * @param int $offset optional, starting point
331
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
332
+     * that may be returned
333
+     * @return IComment[]
334
+     * @since 9.0.0
335
+     */
336
+    public function getForObject(
337
+        $objectType,
338
+        $objectId,
339
+        $limit = 0,
340
+        $offset = 0,
341
+        \DateTime $notOlderThan = null
342
+    ) {
343
+        $comments = [];
344
+
345
+        $qb = $this->dbConn->getQueryBuilder();
346
+        $query = $qb->select('*')
347
+            ->from('comments')
348
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
349
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
350
+            ->orderBy('creation_timestamp', 'DESC')
351
+            ->setParameter('type', $objectType)
352
+            ->setParameter('id', $objectId);
353
+
354
+        if ($limit > 0) {
355
+            $query->setMaxResults($limit);
356
+        }
357
+        if ($offset > 0) {
358
+            $query->setFirstResult($offset);
359
+        }
360
+        if (!is_null($notOlderThan)) {
361
+            $query
362
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
363
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
364
+        }
365
+
366
+        $resultStatement = $query->execute();
367
+        while ($data = $resultStatement->fetch()) {
368
+            $comment = new Comment($this->normalizeDatabaseData($data));
369
+            $this->cache($comment);
370
+            $comments[] = $comment;
371
+        }
372
+        $resultStatement->closeCursor();
373
+
374
+        return $comments;
375
+    }
376
+
377
+    /**
378
+     * @param $objectType string the object type, e.g. 'files'
379
+     * @param $objectId string the id of the object
380
+     * @param \DateTime $notOlderThan optional, timestamp of the oldest comments
381
+     * that may be returned
382
+     * @return Int
383
+     * @since 9.0.0
384
+     */
385
+    public function getNumberOfCommentsForObject($objectType, $objectId, \DateTime $notOlderThan = null) {
386
+        $qb = $this->dbConn->getQueryBuilder();
387
+        $query = $qb->select($qb->createFunction('COUNT(`id`)'))
388
+            ->from('comments')
389
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
390
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
391
+            ->setParameter('type', $objectType)
392
+            ->setParameter('id', $objectId);
393
+
394
+        if (!is_null($notOlderThan)) {
395
+            $query
396
+                ->andWhere($qb->expr()->gt('creation_timestamp', $qb->createParameter('notOlderThan')))
397
+                ->setParameter('notOlderThan', $notOlderThan, 'datetime');
398
+        }
399
+
400
+        $resultStatement = $query->execute();
401
+        $data = $resultStatement->fetch(\PDO::FETCH_NUM);
402
+        $resultStatement->closeCursor();
403
+        return intval($data[0]);
404
+    }
405
+
406
+    /**
407
+     * Get the number of unread comments for all files in a folder
408
+     *
409
+     * @param int $folderId
410
+     * @param IUser $user
411
+     * @return array [$fileId => $unreadCount]
412
+     */
413
+    public function getNumberOfUnreadCommentsForFolder($folderId, IUser $user) {
414
+        $qb = $this->dbConn->getQueryBuilder();
415
+        $castAs = ($this->dbConn->getDatabasePlatform() instanceof MySqlPlatform) ? 'unsigned integer' : 'int';
416
+        $query = $qb->select('fileid', $qb->createFunction(
417
+            'COUNT(' . $qb->getColumnName('c.id') . ')')
418
+        )->from('comments', 'c')
419
+            ->innerJoin('c', 'filecache', 'f', $qb->expr()->andX(
420
+                $qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
421
+                $qb->expr()->eq('f.fileid', $qb->createFunction(
422
+                    'cast(' . $qb->getColumnName('c.object_id') . ' as ' . $castAs . ')'
423
+                ))
424
+            ))
425
+            ->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
426
+                $qb->expr()->eq('m.object_type', $qb->createNamedParameter('files')),
427
+                $qb->expr()->eq('m.object_id', 'c.object_id'),
428
+                $qb->expr()->eq('m.user_id', $qb->createNamedParameter($user->getUID()))
429
+            ))
430
+            ->andWhere($qb->expr()->eq('f.parent', $qb->createNamedParameter($folderId)))
431
+            ->andWhere($qb->expr()->orX(
432
+                $qb->expr()->gt('c.creation_timestamp', 'marker_datetime'),
433
+                $qb->expr()->isNull('marker_datetime')
434
+            ))
435
+            ->groupBy('f.fileid');
436
+
437
+        $resultStatement = $query->execute();
438
+        return array_map(function ($count) {
439
+            return (int)$count;
440
+        }, $resultStatement->fetchAll(\PDO::FETCH_KEY_PAIR));
441
+    }
442
+
443
+    /**
444
+     * creates a new comment and returns it. At this point of time, it is not
445
+     * saved in the used data storage. Use save() after setting other fields
446
+     * of the comment (e.g. message or verb).
447
+     *
448
+     * @param string $actorType the actor type (e.g. 'users')
449
+     * @param string $actorId a user id
450
+     * @param string $objectType the object type the comment is attached to
451
+     * @param string $objectId the object id the comment is attached to
452
+     * @return IComment
453
+     * @since 9.0.0
454
+     */
455
+    public function create($actorType, $actorId, $objectType, $objectId) {
456
+        $comment = new Comment();
457
+        $comment
458
+            ->setActor($actorType, $actorId)
459
+            ->setObject($objectType, $objectId);
460
+        return $comment;
461
+    }
462
+
463
+    /**
464
+     * permanently deletes the comment specified by the ID
465
+     *
466
+     * When the comment has child comments, their parent ID will be changed to
467
+     * the parent ID of the item that is to be deleted.
468
+     *
469
+     * @param string $id
470
+     * @return bool
471
+     * @throws \InvalidArgumentException
472
+     * @since 9.0.0
473
+     */
474
+    public function delete($id) {
475
+        if (!is_string($id)) {
476
+            throw new \InvalidArgumentException('Parameter must be string');
477
+        }
478
+
479
+        try {
480
+            $comment = $this->get($id);
481
+        } catch (\Exception $e) {
482
+            // Ignore exceptions, we just don't fire a hook then
483
+            $comment = null;
484
+        }
485
+
486
+        $qb = $this->dbConn->getQueryBuilder();
487
+        $query = $qb->delete('comments')
488
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
489
+            ->setParameter('id', $id);
490
+
491
+        try {
492
+            $affectedRows = $query->execute();
493
+            $this->uncache($id);
494
+        } catch (DriverException $e) {
495
+            $this->logger->logException($e, ['app' => 'core_comments']);
496
+            return false;
497
+        }
498
+
499
+        if ($affectedRows > 0 && $comment instanceof IComment) {
500
+            $this->sendEvent(CommentsEvent::EVENT_DELETE, $comment);
501
+        }
502
+
503
+        return ($affectedRows > 0);
504
+    }
505
+
506
+    /**
507
+     * saves the comment permanently
508
+     *
509
+     * if the supplied comment has an empty ID, a new entry comment will be
510
+     * saved and the instance updated with the new ID.
511
+     *
512
+     * Otherwise, an existing comment will be updated.
513
+     *
514
+     * Throws NotFoundException when a comment that is to be updated does not
515
+     * exist anymore at this point of time.
516
+     *
517
+     * @param IComment $comment
518
+     * @return bool
519
+     * @throws NotFoundException
520
+     * @since 9.0.0
521
+     */
522
+    public function save(IComment $comment) {
523
+        if ($this->prepareCommentForDatabaseWrite($comment)->getId() === '') {
524
+            $result = $this->insert($comment);
525
+        } else {
526
+            $result = $this->update($comment);
527
+        }
528
+
529
+        if ($result && !!$comment->getParentId()) {
530
+            $this->updateChildrenInformation(
531
+                $comment->getParentId(),
532
+                $comment->getCreationDateTime()
533
+            );
534
+            $this->cache($comment);
535
+        }
536
+
537
+        return $result;
538
+    }
539
+
540
+    /**
541
+     * inserts the provided comment in the database
542
+     *
543
+     * @param IComment $comment
544
+     * @return bool
545
+     */
546
+    protected function insert(IComment &$comment) {
547
+        $qb = $this->dbConn->getQueryBuilder();
548
+        $affectedRows = $qb
549
+            ->insert('comments')
550
+            ->values([
551
+                'parent_id' => $qb->createNamedParameter($comment->getParentId()),
552
+                'topmost_parent_id' => $qb->createNamedParameter($comment->getTopmostParentId()),
553
+                'children_count' => $qb->createNamedParameter($comment->getChildrenCount()),
554
+                'actor_type' => $qb->createNamedParameter($comment->getActorType()),
555
+                'actor_id' => $qb->createNamedParameter($comment->getActorId()),
556
+                'message' => $qb->createNamedParameter($comment->getMessage()),
557
+                'verb' => $qb->createNamedParameter($comment->getVerb()),
558
+                'creation_timestamp' => $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'),
559
+                'latest_child_timestamp' => $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'),
560
+                'object_type' => $qb->createNamedParameter($comment->getObjectType()),
561
+                'object_id' => $qb->createNamedParameter($comment->getObjectId()),
562
+            ])
563
+            ->execute();
564
+
565
+        if ($affectedRows > 0) {
566
+            $comment->setId(strval($qb->getLastInsertId()));
567
+            $this->sendEvent(CommentsEvent::EVENT_ADD, $comment);
568
+        }
569
+
570
+        return $affectedRows > 0;
571
+    }
572
+
573
+    /**
574
+     * updates a Comment data row
575
+     *
576
+     * @param IComment $comment
577
+     * @return bool
578
+     * @throws NotFoundException
579
+     */
580
+    protected function update(IComment $comment) {
581
+        // for properly working preUpdate Events we need the old comments as is
582
+        // in the DB and overcome caching. Also avoid that outdated information stays.
583
+        $this->uncache($comment->getId());
584
+        $this->sendEvent(CommentsEvent::EVENT_PRE_UPDATE, $this->get($comment->getId()));
585
+        $this->uncache($comment->getId());
586
+
587
+        $qb = $this->dbConn->getQueryBuilder();
588
+        $affectedRows = $qb
589
+            ->update('comments')
590
+            ->set('parent_id', $qb->createNamedParameter($comment->getParentId()))
591
+            ->set('topmost_parent_id', $qb->createNamedParameter($comment->getTopmostParentId()))
592
+            ->set('children_count', $qb->createNamedParameter($comment->getChildrenCount()))
593
+            ->set('actor_type', $qb->createNamedParameter($comment->getActorType()))
594
+            ->set('actor_id', $qb->createNamedParameter($comment->getActorId()))
595
+            ->set('message', $qb->createNamedParameter($comment->getMessage()))
596
+            ->set('verb', $qb->createNamedParameter($comment->getVerb()))
597
+            ->set('creation_timestamp', $qb->createNamedParameter($comment->getCreationDateTime(), 'datetime'))
598
+            ->set('latest_child_timestamp', $qb->createNamedParameter($comment->getLatestChildDateTime(), 'datetime'))
599
+            ->set('object_type', $qb->createNamedParameter($comment->getObjectType()))
600
+            ->set('object_id', $qb->createNamedParameter($comment->getObjectId()))
601
+            ->where($qb->expr()->eq('id', $qb->createParameter('id')))
602
+            ->setParameter('id', $comment->getId())
603
+            ->execute();
604
+
605
+        if ($affectedRows === 0) {
606
+            throw new NotFoundException('Comment to update does ceased to exist');
607
+        }
608
+
609
+        $this->sendEvent(CommentsEvent::EVENT_UPDATE, $comment);
610
+
611
+        return $affectedRows > 0;
612
+    }
613
+
614
+    /**
615
+     * removes references to specific actor (e.g. on user delete) of a comment.
616
+     * The comment itself must not get lost/deleted.
617
+     *
618
+     * @param string $actorType the actor type (e.g. 'users')
619
+     * @param string $actorId a user id
620
+     * @return boolean
621
+     * @since 9.0.0
622
+     */
623
+    public function deleteReferencesOfActor($actorType, $actorId) {
624
+        $this->checkRoleParameters('Actor', $actorType, $actorId);
625
+
626
+        $qb = $this->dbConn->getQueryBuilder();
627
+        $affectedRows = $qb
628
+            ->update('comments')
629
+            ->set('actor_type', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
630
+            ->set('actor_id', $qb->createNamedParameter(ICommentsManager::DELETED_USER))
631
+            ->where($qb->expr()->eq('actor_type', $qb->createParameter('type')))
632
+            ->andWhere($qb->expr()->eq('actor_id', $qb->createParameter('id')))
633
+            ->setParameter('type', $actorType)
634
+            ->setParameter('id', $actorId)
635
+            ->execute();
636
+
637
+        $this->commentsCache = [];
638
+
639
+        return is_int($affectedRows);
640
+    }
641
+
642
+    /**
643
+     * deletes all comments made of a specific object (e.g. on file delete)
644
+     *
645
+     * @param string $objectType the object type (e.g. 'files')
646
+     * @param string $objectId e.g. the file id
647
+     * @return boolean
648
+     * @since 9.0.0
649
+     */
650
+    public function deleteCommentsAtObject($objectType, $objectId) {
651
+        $this->checkRoleParameters('Object', $objectType, $objectId);
652
+
653
+        $qb = $this->dbConn->getQueryBuilder();
654
+        $affectedRows = $qb
655
+            ->delete('comments')
656
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('type')))
657
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('id')))
658
+            ->setParameter('type', $objectType)
659
+            ->setParameter('id', $objectId)
660
+            ->execute();
661
+
662
+        $this->commentsCache = [];
663
+
664
+        return is_int($affectedRows);
665
+    }
666
+
667
+    /**
668
+     * deletes the read markers for the specified user
669
+     *
670
+     * @param \OCP\IUser $user
671
+     * @return bool
672
+     * @since 9.0.0
673
+     */
674
+    public function deleteReadMarksFromUser(IUser $user) {
675
+        $qb = $this->dbConn->getQueryBuilder();
676
+        $query = $qb->delete('comments_read_markers')
677
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
678
+            ->setParameter('user_id', $user->getUID());
679
+
680
+        try {
681
+            $affectedRows = $query->execute();
682
+        } catch (DriverException $e) {
683
+            $this->logger->logException($e, ['app' => 'core_comments']);
684
+            return false;
685
+        }
686
+        return ($affectedRows > 0);
687
+    }
688
+
689
+    /**
690
+     * sets the read marker for a given file to the specified date for the
691
+     * provided user
692
+     *
693
+     * @param string $objectType
694
+     * @param string $objectId
695
+     * @param \DateTime $dateTime
696
+     * @param IUser $user
697
+     * @since 9.0.0
698
+     */
699
+    public function setReadMark($objectType, $objectId, \DateTime $dateTime, IUser $user) {
700
+        $this->checkRoleParameters('Object', $objectType, $objectId);
701
+
702
+        $qb = $this->dbConn->getQueryBuilder();
703
+        $values = [
704
+            'user_id' => $qb->createNamedParameter($user->getUID()),
705
+            'marker_datetime' => $qb->createNamedParameter($dateTime, 'datetime'),
706
+            'object_type' => $qb->createNamedParameter($objectType),
707
+            'object_id' => $qb->createNamedParameter($objectId),
708
+        ];
709
+
710
+        // Strategy: try to update, if this does not return affected rows, do an insert.
711
+        $affectedRows = $qb
712
+            ->update('comments_read_markers')
713
+            ->set('user_id', $values['user_id'])
714
+            ->set('marker_datetime', $values['marker_datetime'])
715
+            ->set('object_type', $values['object_type'])
716
+            ->set('object_id', $values['object_id'])
717
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
718
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
719
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
720
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
721
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
722
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
723
+            ->execute();
724
+
725
+        if ($affectedRows > 0) {
726
+            return;
727
+        }
728
+
729
+        $qb->insert('comments_read_markers')
730
+            ->values($values)
731
+            ->execute();
732
+    }
733
+
734
+    /**
735
+     * returns the read marker for a given file to the specified date for the
736
+     * provided user. It returns null, when the marker is not present, i.e.
737
+     * no comments were marked as read.
738
+     *
739
+     * @param string $objectType
740
+     * @param string $objectId
741
+     * @param IUser $user
742
+     * @return \DateTime|null
743
+     * @since 9.0.0
744
+     */
745
+    public function getReadMark($objectType, $objectId, IUser $user) {
746
+        $qb = $this->dbConn->getQueryBuilder();
747
+        $resultStatement = $qb->select('marker_datetime')
748
+            ->from('comments_read_markers')
749
+            ->where($qb->expr()->eq('user_id', $qb->createParameter('user_id')))
750
+            ->andWhere($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
751
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
752
+            ->setParameter('user_id', $user->getUID(), IQueryBuilder::PARAM_STR)
753
+            ->setParameter('object_type', $objectType, IQueryBuilder::PARAM_STR)
754
+            ->setParameter('object_id', $objectId, IQueryBuilder::PARAM_STR)
755
+            ->execute();
756
+
757
+        $data = $resultStatement->fetch();
758
+        $resultStatement->closeCursor();
759
+        if (!$data || is_null($data['marker_datetime'])) {
760
+            return null;
761
+        }
762
+
763
+        return new \DateTime($data['marker_datetime']);
764
+    }
765
+
766
+    /**
767
+     * deletes the read markers on the specified object
768
+     *
769
+     * @param string $objectType
770
+     * @param string $objectId
771
+     * @return bool
772
+     * @since 9.0.0
773
+     */
774
+    public function deleteReadMarksOnObject($objectType, $objectId) {
775
+        $this->checkRoleParameters('Object', $objectType, $objectId);
776
+
777
+        $qb = $this->dbConn->getQueryBuilder();
778
+        $query = $qb->delete('comments_read_markers')
779
+            ->where($qb->expr()->eq('object_type', $qb->createParameter('object_type')))
780
+            ->andWhere($qb->expr()->eq('object_id', $qb->createParameter('object_id')))
781
+            ->setParameter('object_type', $objectType)
782
+            ->setParameter('object_id', $objectId);
783
+
784
+        try {
785
+            $affectedRows = $query->execute();
786
+        } catch (DriverException $e) {
787
+            $this->logger->logException($e, ['app' => 'core_comments']);
788
+            return false;
789
+        }
790
+        return ($affectedRows > 0);
791
+    }
792
+
793
+    /**
794
+     * registers an Entity to the manager, so event notifications can be send
795
+     * to consumers of the comments infrastructure
796
+     *
797
+     * @param \Closure $closure
798
+     */
799
+    public function registerEventHandler(\Closure $closure) {
800
+        $this->eventHandlerClosures[] = $closure;
801
+        $this->eventHandlers = [];
802
+    }
803
+
804
+    /**
805
+     * registers a method that resolves an ID to a display name for a given type
806
+     *
807
+     * @param string $type
808
+     * @param \Closure $closure
809
+     * @throws \OutOfBoundsException
810
+     * @since 11.0.0
811
+     *
812
+     * Only one resolver shall be registered per type. Otherwise a
813
+     * \OutOfBoundsException has to thrown.
814
+     */
815
+    public function registerDisplayNameResolver($type, \Closure $closure) {
816
+        if (!is_string($type)) {
817
+            throw new \InvalidArgumentException('String expected.');
818
+        }
819
+        if (isset($this->displayNameResolvers[$type])) {
820
+            throw new \OutOfBoundsException('Displayname resolver for this type already registered');
821
+        }
822
+        $this->displayNameResolvers[$type] = $closure;
823
+    }
824
+
825
+    /**
826
+     * resolves a given ID of a given Type to a display name.
827
+     *
828
+     * @param string $type
829
+     * @param string $id
830
+     * @return string
831
+     * @throws \OutOfBoundsException
832
+     * @since 11.0.0
833
+     *
834
+     * If a provided type was not registered, an \OutOfBoundsException shall
835
+     * be thrown. It is upon the resolver discretion what to return of the
836
+     * provided ID is unknown. It must be ensured that a string is returned.
837
+     */
838
+    public function resolveDisplayName($type, $id) {
839
+        if (!is_string($type)) {
840
+            throw new \InvalidArgumentException('String expected.');
841
+        }
842
+        if (!isset($this->displayNameResolvers[$type])) {
843
+            throw new \OutOfBoundsException('No Displayname resolver for this type registered');
844
+        }
845
+        return (string)$this->displayNameResolvers[$type]($id);
846
+    }
847
+
848
+    /**
849
+     * returns valid, registered entities
850
+     *
851
+     * @return \OCP\Comments\ICommentsEventHandler[]
852
+     */
853
+    private function getEventHandlers() {
854
+        if (!empty($this->eventHandlers)) {
855
+            return $this->eventHandlers;
856
+        }
857
+
858
+        $this->eventHandlers = [];
859
+        foreach ($this->eventHandlerClosures as $name => $closure) {
860
+            $entity = $closure();
861
+            if (!($entity instanceof ICommentsEventHandler)) {
862
+                throw new \InvalidArgumentException('The given entity does not implement the ICommentsEntity interface');
863
+            }
864
+            $this->eventHandlers[$name] = $entity;
865
+        }
866
+
867
+        return $this->eventHandlers;
868
+    }
869
+
870
+    /**
871
+     * sends notifications to the registered entities
872
+     *
873
+     * @param $eventType
874
+     * @param IComment $comment
875
+     */
876
+    private function sendEvent($eventType, IComment $comment) {
877
+        $entities = $this->getEventHandlers();
878
+        $event = new CommentsEvent($eventType, $comment);
879
+        foreach ($entities as $entity) {
880
+            $entity->handle($event);
881
+        }
882
+    }
883 883
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -191,7 +191,7 @@  discard block
 block discarded – undo
191 191
 			!is_string($type) || empty($type)
192 192
 			|| !is_string($id) || empty($id)
193 193
 		) {
194
-			throw new \InvalidArgumentException($role . ' parameters must be string and not empty');
194
+			throw new \InvalidArgumentException($role.' parameters must be string and not empty');
195 195
 		}
196 196
 	}
197 197
 
@@ -414,12 +414,12 @@  discard block
 block discarded – undo
414 414
 		$qb = $this->dbConn->getQueryBuilder();
415 415
 		$castAs = ($this->dbConn->getDatabasePlatform() instanceof MySqlPlatform) ? 'unsigned integer' : 'int';
416 416
 		$query = $qb->select('fileid', $qb->createFunction(
417
-			'COUNT(' . $qb->getColumnName('c.id') . ')')
417
+			'COUNT('.$qb->getColumnName('c.id').')')
418 418
 		)->from('comments', 'c')
419 419
 			->innerJoin('c', 'filecache', 'f', $qb->expr()->andX(
420 420
 				$qb->expr()->eq('c.object_type', $qb->createNamedParameter('files')),
421 421
 				$qb->expr()->eq('f.fileid', $qb->createFunction(
422
-					'cast(' . $qb->getColumnName('c.object_id') . ' as ' . $castAs . ')'
422
+					'cast('.$qb->getColumnName('c.object_id').' as '.$castAs.')'
423 423
 				))
424 424
 			))
425 425
 			->leftJoin('c', 'comments_read_markers', 'm', $qb->expr()->andX(
@@ -435,8 +435,8 @@  discard block
 block discarded – undo
435 435
 			->groupBy('f.fileid');
436 436
 
437 437
 		$resultStatement = $query->execute();
438
-		return array_map(function ($count) {
439
-			return (int)$count;
438
+		return array_map(function($count) {
439
+			return (int) $count;
440 440
 		}, $resultStatement->fetchAll(\PDO::FETCH_KEY_PAIR));
441 441
 	}
442 442
 
@@ -543,7 +543,7 @@  discard block
 block discarded – undo
543 543
 	 * @param IComment $comment
544 544
 	 * @return bool
545 545
 	 */
546
-	protected function insert(IComment &$comment) {
546
+	protected function insert(IComment & $comment) {
547 547
 		$qb = $this->dbConn->getQueryBuilder();
548 548
 		$affectedRows = $qb
549 549
 			->insert('comments')
@@ -842,7 +842,7 @@  discard block
 block discarded – undo
842 842
 		if (!isset($this->displayNameResolvers[$type])) {
843 843
 			throw new \OutOfBoundsException('No Displayname resolver for this type registered');
844 844
 		}
845
-		return (string)$this->displayNameResolvers[$type]($id);
845
+		return (string) $this->displayNameResolvers[$type]($id);
846 846
 	}
847 847
 
848 848
 	/**
Please login to merge, or discard this patch.