Completed
Push — master ( e5db64...945d9a )
by Schlaefer
05:09 queued 28s
created
app/Model/Entry.php 1 patch
Indentation   +935 added lines, -935 removed lines patch added patch discarded remove patch
@@ -1,8 +1,8 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-	use Saito\User\ForumsUserInterface;
3
+    use Saito\User\ForumsUserInterface;
4 4
 
5
-	App::uses('AppModel', 'Model');
5
+    App::uses('AppModel', 'Model');
6 6
 
7 7
 /**
8 8
  *
@@ -23,225 +23,225 @@  discard block
 block discarded – undo
23 23
  * @td After mlf is gone `edited_by` should conatin a User.id, not the username string.
24 24
  *
25 25
  */
26
-	class Entry extends AppModel {
27
-
28
-		public $name = 'Entry';
29
-
30
-		public $primaryKey = 'id';
31
-
32
-		public $actsAs = [
33
-			'Markup',
34
-			'Containable',
35
-			'Search.Searchable',
36
-			'Tree'
37
-		];
38
-
39
-		public $findMethods = array(
40
-			'feed' => true,
41
-			'entry' => true
42
-		);
43
-
44
-		/**
45
-		 * Fields for search plugin
46
-		 *
47
-		 * @var array
48
-		 */
49
-		public $filterArgs = [
50
-				'subject' => ['type' => 'like'],
51
-				'text' => ['type' => 'like'],
52
-				'name' => ['type' => 'like'],
53
-				'category_id' => ['type' => 'value'],
54
-		];
55
-
56
-		public $belongsTo = array(
57
-			'Category' => array(
58
-				'className' => 'Category',
59
-				'foreignKey' => 'category_id',
60
-			),
61
-			'User' => array(
62
-				'className' => 'User',
63
-				'foreignKey' => 'user_id',
64
-				'counterCache' => true,
65
-			),
66
-		);
67
-
68
-		public $hasMany = array(
69
-			'Bookmark' => array(
70
-				'foreignKey' => 'entry_id',
71
-				'dependent' => true,
72
-			),
73
-			'Esevent' => array(
74
-				'foreignKey' => 'subject',
75
-				'conditions' => array('Esevent.subject' => 'Entry.id'),
76
-			),
77
-			'UserRead' => [
78
-				'foreignKey' => 'entry_id',
79
-				'dependent' => true
80
-			]
81
-		);
82
-
83
-		public $validate = [
84
-				'subject' => [
85
-						'notEmpty' => ['rule' => 'notBlank'],
86
-						'maxLength' => ['rule' => 'validateSubjectMaxLength']
87
-				],
88
-				'category_id' => [
89
-						'notEmpty' => ['rule' => 'notBlank'],
90
-						'numeric' => ['rule' => 'numeric'],
91
-						'isAllowed' => ['rule' => 'validateCategoryIsAllowed']
92
-				],
93
-				'user_id' => ['rule' => 'numeric'],
94
-				'views' => ['rule' => ['comparison', '>=', 0]],
95
-			// used in full text search
96
-				'name' => array()
97
-		];
98
-
99
-		/**
100
-		 * Fields allowed in public output
101
-		 *
102
-		 * @var array
103
-		 */
104
-		protected $_allowedPublicOutputFields = [
105
-			'Entry.id',
106
-			'Entry.pid',
107
-			'Entry.tid',
108
-			'Entry.time',
109
-			'Entry.last_answer',
110
-			'Entry.edited',
111
-			'Entry.edited_by',
112
-			'Entry.user_id',
113
-			'Entry.name',
114
-			'Entry.subject',
115
-			'Entry.category_id',
116
-			'Entry.text',
117
-			'Entry.locked',
118
-			'Entry.fixed',
119
-			'Entry.views',
120
-			'User.username'
121
-		];
122
-
123
-		/**
124
-		 * field list necessary for displaying a thread_line
125
-		 *
126
-		 * Entry.text determine if Entry is n/t
127
-		 *
128
-		 * @var string
129
-		 */
130
-		public $threadLineFieldList = [
131
-			'Entry.id',
132
-			'Entry.pid',
133
-			'Entry.tid',
134
-			'Entry.subject',
135
-			'Entry.text',
136
-			'Entry.time',
137
-			'Entry.fixed',
138
-			'Entry.last_answer',
139
-			'Entry.views',
140
-			'Entry.user_id',
141
-			'Entry.locked',
142
-			'Entry.name',
143
-			'Entry.solves',
144
-
145
-			'User.username',
146
-
147
-			'Category.accession',
148
-			'Category.category',
149
-			'Category.description'
150
-		];
151
-
152
-		/**
153
-		 * fields additional to $threadLineFieldList to show complete entry
154
-		 *
155
-		 * @var string
156
-		 */
157
-		public $showEntryFieldListAdditional = [
158
-			'Entry.edited',
159
-			'Entry.edited_by',
160
-			'Entry.ip',
161
-			'Entry.category_id',
162
-
163
-			'User.id',
164
-			'User.signature',
165
-			'User.user_place'
166
-		];
167
-
168
-		/**
169
-		 * Allowed external user input
170
-		 *
171
-		 * @var array
172
-		 */
173
-		public $allowedInputFields = [
174
-			'create' => [
175
-				'category_id',
176
-				'pid',
177
-				'subject',
178
-				'text'
179
-			],
180
-			'update' => [
181
-				'id',
182
-				'category_id',
183
-				'subject',
184
-				'text'
185
-			]
186
-		];
187
-
188
-		protected $_settings = [
189
-			'edit_period' => 20,
190
-			'subject_maxlength' => 100
191
-		];
26
+    class Entry extends AppModel {
27
+
28
+        public $name = 'Entry';
29
+
30
+        public $primaryKey = 'id';
31
+
32
+        public $actsAs = [
33
+            'Markup',
34
+            'Containable',
35
+            'Search.Searchable',
36
+            'Tree'
37
+        ];
38
+
39
+        public $findMethods = array(
40
+            'feed' => true,
41
+            'entry' => true
42
+        );
43
+
44
+        /**
45
+         * Fields for search plugin
46
+         *
47
+         * @var array
48
+         */
49
+        public $filterArgs = [
50
+                'subject' => ['type' => 'like'],
51
+                'text' => ['type' => 'like'],
52
+                'name' => ['type' => 'like'],
53
+                'category_id' => ['type' => 'value'],
54
+        ];
55
+
56
+        public $belongsTo = array(
57
+            'Category' => array(
58
+                'className' => 'Category',
59
+                'foreignKey' => 'category_id',
60
+            ),
61
+            'User' => array(
62
+                'className' => 'User',
63
+                'foreignKey' => 'user_id',
64
+                'counterCache' => true,
65
+            ),
66
+        );
67
+
68
+        public $hasMany = array(
69
+            'Bookmark' => array(
70
+                'foreignKey' => 'entry_id',
71
+                'dependent' => true,
72
+            ),
73
+            'Esevent' => array(
74
+                'foreignKey' => 'subject',
75
+                'conditions' => array('Esevent.subject' => 'Entry.id'),
76
+            ),
77
+            'UserRead' => [
78
+                'foreignKey' => 'entry_id',
79
+                'dependent' => true
80
+            ]
81
+        );
82
+
83
+        public $validate = [
84
+                'subject' => [
85
+                        'notEmpty' => ['rule' => 'notBlank'],
86
+                        'maxLength' => ['rule' => 'validateSubjectMaxLength']
87
+                ],
88
+                'category_id' => [
89
+                        'notEmpty' => ['rule' => 'notBlank'],
90
+                        'numeric' => ['rule' => 'numeric'],
91
+                        'isAllowed' => ['rule' => 'validateCategoryIsAllowed']
92
+                ],
93
+                'user_id' => ['rule' => 'numeric'],
94
+                'views' => ['rule' => ['comparison', '>=', 0]],
95
+            // used in full text search
96
+                'name' => array()
97
+        ];
98
+
99
+        /**
100
+         * Fields allowed in public output
101
+         *
102
+         * @var array
103
+         */
104
+        protected $_allowedPublicOutputFields = [
105
+            'Entry.id',
106
+            'Entry.pid',
107
+            'Entry.tid',
108
+            'Entry.time',
109
+            'Entry.last_answer',
110
+            'Entry.edited',
111
+            'Entry.edited_by',
112
+            'Entry.user_id',
113
+            'Entry.name',
114
+            'Entry.subject',
115
+            'Entry.category_id',
116
+            'Entry.text',
117
+            'Entry.locked',
118
+            'Entry.fixed',
119
+            'Entry.views',
120
+            'User.username'
121
+        ];
122
+
123
+        /**
124
+         * field list necessary for displaying a thread_line
125
+         *
126
+         * Entry.text determine if Entry is n/t
127
+         *
128
+         * @var string
129
+         */
130
+        public $threadLineFieldList = [
131
+            'Entry.id',
132
+            'Entry.pid',
133
+            'Entry.tid',
134
+            'Entry.subject',
135
+            'Entry.text',
136
+            'Entry.time',
137
+            'Entry.fixed',
138
+            'Entry.last_answer',
139
+            'Entry.views',
140
+            'Entry.user_id',
141
+            'Entry.locked',
142
+            'Entry.name',
143
+            'Entry.solves',
144
+
145
+            'User.username',
146
+
147
+            'Category.accession',
148
+            'Category.category',
149
+            'Category.description'
150
+        ];
151
+
152
+        /**
153
+         * fields additional to $threadLineFieldList to show complete entry
154
+         *
155
+         * @var string
156
+         */
157
+        public $showEntryFieldListAdditional = [
158
+            'Entry.edited',
159
+            'Entry.edited_by',
160
+            'Entry.ip',
161
+            'Entry.category_id',
162
+
163
+            'User.id',
164
+            'User.signature',
165
+            'User.user_place'
166
+        ];
167
+
168
+        /**
169
+         * Allowed external user input
170
+         *
171
+         * @var array
172
+         */
173
+        public $allowedInputFields = [
174
+            'create' => [
175
+                'category_id',
176
+                'pid',
177
+                'subject',
178
+                'text'
179
+            ],
180
+            'update' => [
181
+                'id',
182
+                'category_id',
183
+                'subject',
184
+                'text'
185
+            ]
186
+        ];
187
+
188
+        protected $_settings = [
189
+            'edit_period' => 20,
190
+            'subject_maxlength' => 100
191
+        ];
192 192
 
193 193
 /**
194 194
  * Caching for isRoot()
195 195
  *
196 196
  * @var array
197 197
  */
198
-		protected $_isRoot = [];
199
-
200
-		/**
201
-		 * @param ForumsUserInterface $User
202
-		 * @param array $options
203
-		 * @return array|mixed
204
-		 */
205
-		public function getRecentEntries(CurrentUserComponent $User, array $options = []) {
206
-			Stopwatch::start('Model->User->getRecentEntries()');
207
-
208
-			$options += [
209
-				'user_id' => null,
210
-				'limit' => 10,
211
-				'category_id' => $User->Categories->getAllowed()
212
-			];
213
-
214
-			$_cacheKey = 'Entry.recentEntries-' . md5(serialize($options));
215
-			$_cachedEntry = Cache::read($_cacheKey, 'entries');
216
-			if ($_cachedEntry) {
217
-				Stopwatch::stop('Model->User->getRecentEntries()');
218
-				return $_cachedEntry;
219
-			}
220
-
221
-			$conditions = array();
222
-			if ($options['user_id'] !== null) {
223
-				$conditions[]['Entry.user_id'] = $options['user_id'];
224
-			}
225
-			if ($options['category_id'] !== null):
226
-				$conditions[]['Entry.category_id'] = $options['category_id'];
227
-			endif;
228
-
229
-			$result = $this->find(
230
-				'all',
231
-				[
232
-					'contain' => array('User', 'Category'),
233
-					'fields' => $this->threadLineFieldList,
234
-					'conditions' => $conditions,
235
-					'limit' => $options['limit'],
236
-					'order' => 'time DESC'
237
-				]
238
-			);
239
-
240
-			Cache::write($_cacheKey, $result, 'entries');
241
-
242
-			Stopwatch::stop('Model->User->getRecentEntries()');
243
-			return $result;
244
-		}
198
+        protected $_isRoot = [];
199
+
200
+        /**
201
+         * @param ForumsUserInterface $User
202
+         * @param array $options
203
+         * @return array|mixed
204
+         */
205
+        public function getRecentEntries(CurrentUserComponent $User, array $options = []) {
206
+            Stopwatch::start('Model->User->getRecentEntries()');
207
+
208
+            $options += [
209
+                'user_id' => null,
210
+                'limit' => 10,
211
+                'category_id' => $User->Categories->getAllowed()
212
+            ];
213
+
214
+            $_cacheKey = 'Entry.recentEntries-' . md5(serialize($options));
215
+            $_cachedEntry = Cache::read($_cacheKey, 'entries');
216
+            if ($_cachedEntry) {
217
+                Stopwatch::stop('Model->User->getRecentEntries()');
218
+                return $_cachedEntry;
219
+            }
220
+
221
+            $conditions = array();
222
+            if ($options['user_id'] !== null) {
223
+                $conditions[]['Entry.user_id'] = $options['user_id'];
224
+            }
225
+            if ($options['category_id'] !== null):
226
+                $conditions[]['Entry.category_id'] = $options['category_id'];
227
+            endif;
228
+
229
+            $result = $this->find(
230
+                'all',
231
+                [
232
+                    'contain' => array('User', 'Category'),
233
+                    'fields' => $this->threadLineFieldList,
234
+                    'conditions' => $conditions,
235
+                    'limit' => $options['limit'],
236
+                    'order' => 'time DESC'
237
+                ]
238
+            );
239
+
240
+            Cache::write($_cacheKey, $result, 'entries');
241
+
242
+            Stopwatch::stop('Model->User->getRecentEntries()');
243
+            return $result;
244
+        }
245 245
 
246 246
 /**
247 247
  * Finds the thread-id for a posting
@@ -250,233 +250,233 @@  discard block
 block discarded – undo
250 250
  * @return int Thread-Id
251 251
  * @throws UnexpectedValueException
252 252
  */
253
-		public function getThreadId($id) {
254
-			$entry = $this->find(
255
-				'first',
256
-				[
257
-					'contain' => false,
258
-					'conditions' => ['Entry.id' => $id],
259
-					'fields' => 'Entry.tid'
260
-
261
-				]
262
-			);
263
-			if ($entry == false) {
264
-				throw new UnexpectedValueException('Posting not found. Posting-Id: ' . $id);
265
-			}
266
-			return $entry['Entry']['tid'];
267
-		}
253
+        public function getThreadId($id) {
254
+            $entry = $this->find(
255
+                'first',
256
+                [
257
+                    'contain' => false,
258
+                    'conditions' => ['Entry.id' => $id],
259
+                    'fields' => 'Entry.tid'
260
+
261
+                ]
262
+            );
263
+            if ($entry == false) {
264
+                throw new UnexpectedValueException('Posting not found. Posting-Id: ' . $id);
265
+            }
266
+            return $entry['Entry']['tid'];
267
+        }
268 268
 
269 269
 /**
270 270
  * Shorthand for reading an entry with full data
271 271
  */
272
-		public function get($id) {
273
-			return $this->find('entry',
274
-					['conditions' => [$this->alias . '.id' => $id]]);
275
-		}
272
+        public function get($id) {
273
+            return $this->find('entry',
274
+                    ['conditions' => [$this->alias . '.id' => $id]]);
275
+        }
276 276
 
277 277
 /**
278 278
  * @param $id
279 279
  * @return mixed
280 280
  * @throws UnexpectedValueException
281 281
  */
282
-		public function getParentId($id) {
283
-			$entry = $this->find(
284
-				'first',
285
-				[
286
-					'contain' => false,
287
-					'conditions' => ['Entry.id' => $id],
288
-					'fields' => 'Entry.pid'
289
-
290
-				]
291
-			);
292
-			if ($entry == false) {
293
-				throw new UnexpectedValueException('Posting not found. Posting-Id: ' . $id);
294
-			}
295
-			return $entry['Entry']['pid'];
296
-		}
297
-
298
-		/**
299
-		 * creates a new root or child entry for a node
300
-		 *
301
-		 * fields in $data are filtered
302
-		 *
303
-		 * @param $data
304
-		 * @return array|bool|mixed
305
-		 */
306
-		public function createPosting($data) {
307
-			if (!isset($data[$this->alias]['pid'])) {
308
-				$data[$this->alias]['pid'] = 0;
309
-			}
310
-
311
-			if (isset($data[$this->alias]['subject']) === false) {
312
-				return false;
313
-			}
314
-
315
-			try {
316
-				$this->prepare($data, ['preFilterFields' => 'create']);
317
-			} catch (Exception $e) {
318
-				return false;
319
-			}
320
-
321
-			$data[$this->alias]['user_id'] = $this->CurrentUser->getId();
322
-			$data[$this->alias]['name'] = $this->CurrentUser['username'];
323
-
324
-			$data[$this->alias]['time'] = bDate();
325
-			$data[$this->alias]['last_answer'] = bDate();
326
-			$data[$this->alias]['ip'] = self::_getIp();
327
-
328
-			$this->create();
329
-			$_newPosting = $this->save($data);
330
-
331
-			if ($_newPosting === false) {
332
-				return false;
333
-			}
334
-
335
-			$_newPostingId = $this->id;
336
-
337
-			// make sure we pass the complete ['Entry'] dataset to events
338
-			$this->contain();
339
-			$_newPosting = $this->read();
340
-
341
-			if ($this->isRoot($data)) {
342
-				// thread-id of new thread is its own id
343
-				if ($this->save(['tid' => $_newPostingId], false, ['tid']) === false) {
344
-					// @td raise error and/or roll back new entry
345
-					return false;
346
-				} else {
347
-					$_newPosting[$this->alias]['tid'] = $_newPostingId;
348
-					$this->Category->id = $data[$this->alias]['category_id'];
349
-					$this->Category->updateThreadCounter();
350
-				}
351
-				$this->_dispatchEvent(
352
-					'Model.Thread.create',
353
-					[
354
-						'subject' => $_newPosting[$this->alias]['id'],
355
-						'data' => $_newPosting
356
-					]
357
-				);
358
-			} else {
359
-				// update last answer time of root entry
360
-				$this->clear();
361
-				$this->id = $_newPosting[$this->alias]['tid'];
362
-				$this->set('last_answer', $_newPosting[$this->alias]['last_answer']);
363
-				if ($this->save() === false) {
364
-					// @td raise error and/or roll back new entry
365
-					return false;
366
-				}
367
-
368
-				$this->_dispatchEvent(
369
-					'Model.Entry.replyToEntry',
370
-					[
371
-						'subject' => $_newPosting[$this->alias]['pid'],
372
-						'data' => $_newPosting
373
-					]
374
-				);
375
-				$this->_dispatchEvent(
376
-					'Model.Entry.replyToThread',
377
-					[
378
-						'subject' => $_newPosting[$this->alias]['tid'],
379
-						'data' => $_newPosting
380
-					]
381
-				);
382
-			}
383
-
384
-			$this->id = $_newPostingId;
385
-			$_newPosting[$this->alias]['subject'] = Sanitize::html($_newPosting[$this->alias]['subject']);
386
-			$_newPosting[$this->alias]['text'] = Sanitize::html($_newPosting[$this->alias]['text']);
387
-			return $_newPosting;
388
-		}
389
-
390
-		/**
391
-		 * Updates a posting
392
-		 *
393
-		 * fields in $data are filtered except for $id!
394
-		 *
395
-		 * @param $data
396
-		 * @param null $CurrentUser
397
-		 * @return array|mixed
398
-		 * @throws NotFoundException
399
-		 * @throws InvalidArgumentException
400
-		 */
401
-		public function update($data, $CurrentUser = null) {
402
-			if ($CurrentUser !== null) {
403
-				$this->CurrentUser = $CurrentUser;
404
-			}
405
-
406
-			if (empty($data[$this->alias]['id'])) {
407
-				throw new InvalidArgumentException('Missing entry id in arguments.');
408
-			}
409
-
410
-			$id = $data[$this->alias]['id'];
411
-			if (!$this->exists($id)) {
412
-				throw new NotFoundException(sprintf('Entry with id `%s` not found.', $id));
413
-			}
414
-
415
-			$this->prepare($data, ['preFilterFields' => 'update']);
416
-
417
-			// prevents normal user of changing category of complete thread when answering
418
-			// @todo this should be refactored together with the change category handling in beforeSave()
419
-			if ($this->isRoot($data) === false) {
420
-				unset($data[$this->alias]['category_id']);
421
-			}
422
-
423
-			$data[$this->alias]['edited'] = bDate();
424
-			$data[$this->alias]['edited_by'] = $this->CurrentUser['username'];
425
-
426
-			$this->validator()->add(
427
-				'edited_by',
428
-				'isEditingAllowed',
429
-				[
430
-					'rule' => 'validateEditingAllowed'
431
-				]
432
-			);
433
-
434
-			$result = $this->save($data);
435
-
436
-			if ($result) {
437
-				$this->contain();
438
-				$result = $this->read() + $data;
439
-				$this->_dispatchEvent(
440
-					'Model.Entry.update',
441
-					[
442
-						'subject' => $result[$this->alias]['id'],
443
-						'data' => $result
444
-					]
445
-				);
446
-			}
447
-
448
-			return $result;
449
-		}
450
-
451
-		/**
452
-		 * Update view counter on all entries in a thread
453
-		 *
454
-		 * Note that this function unbinds the model associations for performance.
455
-		 * Otherwise updateAll() left joins all associated models.
456
-		 *
457
-		 * @param $tid thread-ID
458
-		 * @param $uid entries with this user-id are not updated
459
-		 */
460
-		public function threadIncrementViews($tid, $uid = null) {
461
-			Stopwatch::start('Entry::threadIncrementViews');
462
-			$_where = ['Entry.tid' => $tid];
463
-			if ($uid && is_int($uid)) {
464
-				$_where['Entry.user_id !='] = $uid;
465
-			}
466
-			// $_belongsTo = $this->belongsTo;
467
-			$this->unbindModel(['belongsTo' => array_keys($this->belongsTo)]);
468
-			$this->updateAll(['Entry.views' => 'Entry.views + 1'], $_where);
469
-			// $this->bindModel(['belongsTo' => $_belongsTo]);
470
-			Stopwatch::stop('Entry::threadIncrementViews');
471
-		}
282
+        public function getParentId($id) {
283
+            $entry = $this->find(
284
+                'first',
285
+                [
286
+                    'contain' => false,
287
+                    'conditions' => ['Entry.id' => $id],
288
+                    'fields' => 'Entry.pid'
289
+
290
+                ]
291
+            );
292
+            if ($entry == false) {
293
+                throw new UnexpectedValueException('Posting not found. Posting-Id: ' . $id);
294
+            }
295
+            return $entry['Entry']['pid'];
296
+        }
297
+
298
+        /**
299
+         * creates a new root or child entry for a node
300
+         *
301
+         * fields in $data are filtered
302
+         *
303
+         * @param $data
304
+         * @return array|bool|mixed
305
+         */
306
+        public function createPosting($data) {
307
+            if (!isset($data[$this->alias]['pid'])) {
308
+                $data[$this->alias]['pid'] = 0;
309
+            }
310
+
311
+            if (isset($data[$this->alias]['subject']) === false) {
312
+                return false;
313
+            }
314
+
315
+            try {
316
+                $this->prepare($data, ['preFilterFields' => 'create']);
317
+            } catch (Exception $e) {
318
+                return false;
319
+            }
320
+
321
+            $data[$this->alias]['user_id'] = $this->CurrentUser->getId();
322
+            $data[$this->alias]['name'] = $this->CurrentUser['username'];
323
+
324
+            $data[$this->alias]['time'] = bDate();
325
+            $data[$this->alias]['last_answer'] = bDate();
326
+            $data[$this->alias]['ip'] = self::_getIp();
327
+
328
+            $this->create();
329
+            $_newPosting = $this->save($data);
330
+
331
+            if ($_newPosting === false) {
332
+                return false;
333
+            }
334
+
335
+            $_newPostingId = $this->id;
336
+
337
+            // make sure we pass the complete ['Entry'] dataset to events
338
+            $this->contain();
339
+            $_newPosting = $this->read();
340
+
341
+            if ($this->isRoot($data)) {
342
+                // thread-id of new thread is its own id
343
+                if ($this->save(['tid' => $_newPostingId], false, ['tid']) === false) {
344
+                    // @td raise error and/or roll back new entry
345
+                    return false;
346
+                } else {
347
+                    $_newPosting[$this->alias]['tid'] = $_newPostingId;
348
+                    $this->Category->id = $data[$this->alias]['category_id'];
349
+                    $this->Category->updateThreadCounter();
350
+                }
351
+                $this->_dispatchEvent(
352
+                    'Model.Thread.create',
353
+                    [
354
+                        'subject' => $_newPosting[$this->alias]['id'],
355
+                        'data' => $_newPosting
356
+                    ]
357
+                );
358
+            } else {
359
+                // update last answer time of root entry
360
+                $this->clear();
361
+                $this->id = $_newPosting[$this->alias]['tid'];
362
+                $this->set('last_answer', $_newPosting[$this->alias]['last_answer']);
363
+                if ($this->save() === false) {
364
+                    // @td raise error and/or roll back new entry
365
+                    return false;
366
+                }
367
+
368
+                $this->_dispatchEvent(
369
+                    'Model.Entry.replyToEntry',
370
+                    [
371
+                        'subject' => $_newPosting[$this->alias]['pid'],
372
+                        'data' => $_newPosting
373
+                    ]
374
+                );
375
+                $this->_dispatchEvent(
376
+                    'Model.Entry.replyToThread',
377
+                    [
378
+                        'subject' => $_newPosting[$this->alias]['tid'],
379
+                        'data' => $_newPosting
380
+                    ]
381
+                );
382
+            }
383
+
384
+            $this->id = $_newPostingId;
385
+            $_newPosting[$this->alias]['subject'] = Sanitize::html($_newPosting[$this->alias]['subject']);
386
+            $_newPosting[$this->alias]['text'] = Sanitize::html($_newPosting[$this->alias]['text']);
387
+            return $_newPosting;
388
+        }
389
+
390
+        /**
391
+         * Updates a posting
392
+         *
393
+         * fields in $data are filtered except for $id!
394
+         *
395
+         * @param $data
396
+         * @param null $CurrentUser
397
+         * @return array|mixed
398
+         * @throws NotFoundException
399
+         * @throws InvalidArgumentException
400
+         */
401
+        public function update($data, $CurrentUser = null) {
402
+            if ($CurrentUser !== null) {
403
+                $this->CurrentUser = $CurrentUser;
404
+            }
405
+
406
+            if (empty($data[$this->alias]['id'])) {
407
+                throw new InvalidArgumentException('Missing entry id in arguments.');
408
+            }
409
+
410
+            $id = $data[$this->alias]['id'];
411
+            if (!$this->exists($id)) {
412
+                throw new NotFoundException(sprintf('Entry with id `%s` not found.', $id));
413
+            }
414
+
415
+            $this->prepare($data, ['preFilterFields' => 'update']);
416
+
417
+            // prevents normal user of changing category of complete thread when answering
418
+            // @todo this should be refactored together with the change category handling in beforeSave()
419
+            if ($this->isRoot($data) === false) {
420
+                unset($data[$this->alias]['category_id']);
421
+            }
422
+
423
+            $data[$this->alias]['edited'] = bDate();
424
+            $data[$this->alias]['edited_by'] = $this->CurrentUser['username'];
425
+
426
+            $this->validator()->add(
427
+                'edited_by',
428
+                'isEditingAllowed',
429
+                [
430
+                    'rule' => 'validateEditingAllowed'
431
+                ]
432
+            );
433
+
434
+            $result = $this->save($data);
435
+
436
+            if ($result) {
437
+                $this->contain();
438
+                $result = $this->read() + $data;
439
+                $this->_dispatchEvent(
440
+                    'Model.Entry.update',
441
+                    [
442
+                        'subject' => $result[$this->alias]['id'],
443
+                        'data' => $result
444
+                    ]
445
+                );
446
+            }
447
+
448
+            return $result;
449
+        }
450
+
451
+        /**
452
+         * Update view counter on all entries in a thread
453
+         *
454
+         * Note that this function unbinds the model associations for performance.
455
+         * Otherwise updateAll() left joins all associated models.
456
+         *
457
+         * @param $tid thread-ID
458
+         * @param $uid entries with this user-id are not updated
459
+         */
460
+        public function threadIncrementViews($tid, $uid = null) {
461
+            Stopwatch::start('Entry::threadIncrementViews');
462
+            $_where = ['Entry.tid' => $tid];
463
+            if ($uid && is_int($uid)) {
464
+                $_where['Entry.user_id !='] = $uid;
465
+            }
466
+            // $_belongsTo = $this->belongsTo;
467
+            $this->unbindModel(['belongsTo' => array_keys($this->belongsTo)]);
468
+            $this->updateAll(['Entry.views' => 'Entry.views + 1'], $_where);
469
+            // $this->bindModel(['belongsTo' => $_belongsTo]);
470
+            Stopwatch::stop('Entry::threadIncrementViews');
471
+        }
472 472
 
473 473
 /**
474 474
  *
475 475
  * @mb `views` into extra related table if performance becomes a problem
476 476
  */
477
-		public function incrementViews($id, $amount = 1) {
478
-			$this->increment($id, 'views', $amount);
479
-		}
477
+        public function incrementViews($id, $amount = 1) {
478
+            $this->increment($id, 'views', $amount);
479
+        }
480 480
 
481 481
 /**
482 482
  * tree of a single node and its subentries
@@ -489,77 +489,77 @@  discard block
 block discarded – undo
489 489
  * @param array $options
490 490
  * @return array tree
491 491
  */
492
-		public function treeForNode($id, $options = array()) {
493
-			$options += [
494
-				'root' => false,
495
-				'complete' => false
496
-			];
497
-
498
-			if ($options['root']) {
499
-				$tid = $id;
500
-			} else {
501
-				$tid = $this->getThreadId($id);
502
-			}
503
-
504
-			$fields = null;
505
-			if ($options['complete']) {
506
-				$fields = array_merge($this->threadLineFieldList, $this->showEntryFieldListAdditional);
507
-			}
508
-
509
-			$tree = $this->treesForThreads([$tid], null, $fields);
510
-
511
-			if ((int)$tid !== (int)$id) {
512
-				$tree = $this->treeGetSubtree($tree, $id);
513
-			}
514
-
515
-			return $tree;
516
-		}
517
-
518
-		/**
519
-		 * trees for multiple tids
520
-		 *
521
-		 * @param $ids
522
-		 * @param null $order
523
-		 * @param null $fieldlist
524
-		 * @return array|bool false if no threads or array with Posting
525
-		 */
526
-		public function treesForThreads($ids, $order = null, $fieldlist = null) {
527
-			if (empty($ids)) {
528
-				return [];
529
-			}
530
-
531
-			Stopwatch::start('Model->Entries->treeForThreads() DB');
532
-
533
-			if (empty($order)) {
534
-				$order = 'last_answer ASC';
535
-			}
536
-
537
-			if ($fieldlist === null) {
538
-				$fieldlist = $this->threadLineFieldList;
539
-			}
540
-
541
-			$entries = $this->_getThreadEntries(
542
-				$ids,
543
-				['order' => $order, 'fields' => $fieldlist]
544
-			);
545
-
546
-			Stopwatch::stop('Model->Entries->treeForThreads() DB');
547
-			Stopwatch::start('Model->Entries->treeForThreads() CPU');
548
-
549
-			$threads = false;
550
-			if ($entries) {
551
-				$threads = [];
552
-				$entries = $this->treeBuild($entries);
553
-				foreach ($entries as $thread) {
554
-					$id = (int)$thread['Entry']['tid'];
555
-					$threads[$id] = $thread;
556
-				}
557
-			}
558
-
559
-			Stopwatch::stop('Model->Entries->treeForThreads() CPU');
560
-
561
-			return $threads;
562
-		}
492
+        public function treeForNode($id, $options = array()) {
493
+            $options += [
494
+                'root' => false,
495
+                'complete' => false
496
+            ];
497
+
498
+            if ($options['root']) {
499
+                $tid = $id;
500
+            } else {
501
+                $tid = $this->getThreadId($id);
502
+            }
503
+
504
+            $fields = null;
505
+            if ($options['complete']) {
506
+                $fields = array_merge($this->threadLineFieldList, $this->showEntryFieldListAdditional);
507
+            }
508
+
509
+            $tree = $this->treesForThreads([$tid], null, $fields);
510
+
511
+            if ((int)$tid !== (int)$id) {
512
+                $tree = $this->treeGetSubtree($tree, $id);
513
+            }
514
+
515
+            return $tree;
516
+        }
517
+
518
+        /**
519
+         * trees for multiple tids
520
+         *
521
+         * @param $ids
522
+         * @param null $order
523
+         * @param null $fieldlist
524
+         * @return array|bool false if no threads or array with Posting
525
+         */
526
+        public function treesForThreads($ids, $order = null, $fieldlist = null) {
527
+            if (empty($ids)) {
528
+                return [];
529
+            }
530
+
531
+            Stopwatch::start('Model->Entries->treeForThreads() DB');
532
+
533
+            if (empty($order)) {
534
+                $order = 'last_answer ASC';
535
+            }
536
+
537
+            if ($fieldlist === null) {
538
+                $fieldlist = $this->threadLineFieldList;
539
+            }
540
+
541
+            $entries = $this->_getThreadEntries(
542
+                $ids,
543
+                ['order' => $order, 'fields' => $fieldlist]
544
+            );
545
+
546
+            Stopwatch::stop('Model->Entries->treeForThreads() DB');
547
+            Stopwatch::start('Model->Entries->treeForThreads() CPU');
548
+
549
+            $threads = false;
550
+            if ($entries) {
551
+                $threads = [];
552
+                $entries = $this->treeBuild($entries);
553
+                foreach ($entries as $thread) {
554
+                    $id = (int)$thread['Entry']['tid'];
555
+                    $threads[$id] = $thread;
556
+                }
557
+            }
558
+
559
+            Stopwatch::stop('Model->Entries->treeForThreads() CPU');
560
+
561
+            return $threads;
562
+        }
563 563
 
564 564
 /**
565 565
  * @param       $tid
@@ -574,82 +574,82 @@  discard block
 block discarded – undo
574 574
  *  )
575 575
  * </pre>
576 576
  */
577
-		protected function _getThreadEntries($tid, array $params = []) {
578
-			$params += [
579
-				'fields' => $this->threadLineFieldList,
580
-				'order' => 'last_answer ASC'
581
-			];
582
-			$threads = $this->find(
583
-				'all',
584
-				[
585
-					'conditions' => ['tid' => $tid],
586
-					'contain' => ['User', 'Category'],
587
-					'fields' => $params['fields'],
588
-					'order' => $params['order']
589
-				]
590
-			);
591
-
592
-			return $threads;
593
-		}
594
-
595
-		/**
596
-		 * Marks a sub-entry as solution to a root entry
597
-		 *
598
-		 * @param $id
599
-		 * @return bool
600
-		 * @throws InvalidArgumentException
601
-		 * @throws ForbiddenException
602
-		 */
603
-		public function toggleSolve($id) {
604
-			$entry = $this->get($id);
605
-			if (empty($entry) || $this->isRoot($entry)) {
606
-				throw new InvalidArgumentException;
607
-			}
608
-
609
-			$root = $this->get($entry['Entry']['tid']);
610
-			if ((int)$root['User']['id'] !== $this->CurrentUser->getId()) {
611
-				throw new ForbiddenException;
612
-			}
613
-
614
-			if ($entry[$this->alias]['solves']) {
615
-				$value = 0;
616
-			} else {
617
-				$value = $entry[$this->alias]['tid'];
618
-			}
619
-			$this->id = $id;
620
-			$success = $this->saveField('solves', $value);
621
-			if (!$success) {
622
-				return $success;
623
-			}
624
-			$this->_dispatchEvent('Model.Entry.update',
625
-					['subject' => $id, 'data' => $entry]);
626
-			$entry[$this->alias]['solves'] = $value;
627
-			return $success;
628
-		}
629
-
630
-		public function toggle($key) {
631
-			$result = parent::toggle($key);
632
-			if ($key === 'locked') {
633
-				$this->_threadLock($result);
634
-			}
635
-
636
-			$this->contain();
637
-			$entry = $this->read();
638
-
639
-			$this->_dispatchEvent(
640
-				'Model.Entry.update',
641
-				[
642
-					'subject' => $entry[$this->alias]['id'],
643
-					'data' => $entry
644
-				]
645
-			);
646
-
647
-			return $result;
648
-		}
649
-
650
-		public function beforeFind($queryData) {
651
-			parent::beforeFind($queryData);
652
-			/*
577
+        protected function _getThreadEntries($tid, array $params = []) {
578
+            $params += [
579
+                'fields' => $this->threadLineFieldList,
580
+                'order' => 'last_answer ASC'
581
+            ];
582
+            $threads = $this->find(
583
+                'all',
584
+                [
585
+                    'conditions' => ['tid' => $tid],
586
+                    'contain' => ['User', 'Category'],
587
+                    'fields' => $params['fields'],
588
+                    'order' => $params['order']
589
+                ]
590
+            );
591
+
592
+            return $threads;
593
+        }
594
+
595
+        /**
596
+         * Marks a sub-entry as solution to a root entry
597
+         *
598
+         * @param $id
599
+         * @return bool
600
+         * @throws InvalidArgumentException
601
+         * @throws ForbiddenException
602
+         */
603
+        public function toggleSolve($id) {
604
+            $entry = $this->get($id);
605
+            if (empty($entry) || $this->isRoot($entry)) {
606
+                throw new InvalidArgumentException;
607
+            }
608
+
609
+            $root = $this->get($entry['Entry']['tid']);
610
+            if ((int)$root['User']['id'] !== $this->CurrentUser->getId()) {
611
+                throw new ForbiddenException;
612
+            }
613
+
614
+            if ($entry[$this->alias]['solves']) {
615
+                $value = 0;
616
+            } else {
617
+                $value = $entry[$this->alias]['tid'];
618
+            }
619
+            $this->id = $id;
620
+            $success = $this->saveField('solves', $value);
621
+            if (!$success) {
622
+                return $success;
623
+            }
624
+            $this->_dispatchEvent('Model.Entry.update',
625
+                    ['subject' => $id, 'data' => $entry]);
626
+            $entry[$this->alias]['solves'] = $value;
627
+            return $success;
628
+        }
629
+
630
+        public function toggle($key) {
631
+            $result = parent::toggle($key);
632
+            if ($key === 'locked') {
633
+                $this->_threadLock($result);
634
+            }
635
+
636
+            $this->contain();
637
+            $entry = $this->read();
638
+
639
+            $this->_dispatchEvent(
640
+                'Model.Entry.update',
641
+                [
642
+                    'subject' => $entry[$this->alias]['id'],
643
+                    'data' => $entry
644
+                ]
645
+            );
646
+
647
+            return $result;
648
+        }
649
+
650
+        public function beforeFind($queryData) {
651
+            parent::beforeFind($queryData);
652
+            /*
653 653
 				* workarround for possible cakephp join error for associated tables
654 654
 				* and virtual fields
655 655
 				*
@@ -659,17 +659,17 @@  discard block
 block discarded – undo
659 659
 				*
660 660
 				* checkout in cakephp mailing list/bug tracker
661 661
 				*/
662
-			$this->User->virtualFields = null;
663
-		}
662
+            $this->User->virtualFields = null;
663
+        }
664 664
 
665
-		public function beforeValidate($options = array()) {
666
-			parent::beforeValidate($options);
665
+        public function beforeValidate($options = array()) {
666
+            parent::beforeValidate($options);
667 667
 
668
-			//* in n/t posting delete unnecessary body text
669
-			if (isset($this->data['Entry']['text'])) {
670
-				$this->data['Entry']['text'] = rtrim($this->data['Entry']['text']);
671
-			}
672
-		}
668
+            //* in n/t posting delete unnecessary body text
669
+            if (isset($this->data['Entry']['text'])) {
670
+                $this->data['Entry']['text'] = rtrim($this->data['Entry']['text']);
671
+            }
672
+        }
673 673
 
674 674
 /**
675 675
  * Deletes entry and all it's subentries and associated data
@@ -677,43 +677,43 @@  discard block
 block discarded – undo
677 677
  * @return bool
678 678
  * @throws Exception
679 679
  */
680
-		public function deleteNode($id = null) {
681
-			if (empty($id)) {
682
-				$id = $this->id;
683
-			}
684
-
685
-			$this->contain();
686
-			$entry = $this->findById($id);
687
-
688
-			if (empty($entry)) {
689
-				throw new Exception;
690
-			}
691
-
692
-			$_idsToDelete = $this->getIdsForNode($id);
693
-			$success = $this->deleteAll(
694
-				[$this->alias . '.id' => $_idsToDelete],
695
-				true,
696
-				true
697
-			);
698
-
699
-			if ($success):
700
-				if ($this->isRoot($entry)) {
701
-					$this->Category->id = $entry['Entry']['category_id'];
702
-					$this->Category->updateThreadCounter();
703
-					$this->Esevent->deleteSubject($id, 'thread');
704
-				}
705
-				foreach ($_idsToDelete as $_entryId) {
706
-					$this->Esevent->deleteSubject($_entryId, 'entry');
707
-				}
708
-
709
-				$this->_dispatchEvent(
710
-					'Model.Thread.change',
711
-					['subject' => $entry[$this->alias]['tid']]
712
-				);
713
-			endif;
714
-
715
-			return $success;
716
-		}
680
+        public function deleteNode($id = null) {
681
+            if (empty($id)) {
682
+                $id = $this->id;
683
+            }
684
+
685
+            $this->contain();
686
+            $entry = $this->findById($id);
687
+
688
+            if (empty($entry)) {
689
+                throw new Exception;
690
+            }
691
+
692
+            $_idsToDelete = $this->getIdsForNode($id);
693
+            $success = $this->deleteAll(
694
+                [$this->alias . '.id' => $_idsToDelete],
695
+                true,
696
+                true
697
+            );
698
+
699
+            if ($success):
700
+                if ($this->isRoot($entry)) {
701
+                    $this->Category->id = $entry['Entry']['category_id'];
702
+                    $this->Category->updateThreadCounter();
703
+                    $this->Esevent->deleteSubject($id, 'thread');
704
+                }
705
+                foreach ($_idsToDelete as $_entryId) {
706
+                    $this->Esevent->deleteSubject($_entryId, 'entry');
707
+                }
708
+
709
+                $this->_dispatchEvent(
710
+                    'Model.Thread.change',
711
+                    ['subject' => $entry[$this->alias]['tid']]
712
+                );
713
+            endif;
714
+
715
+            return $success;
716
+        }
717 717
 
718 718
 /**
719 719
  * Get the ID of all subentries of and including entry $id
@@ -721,16 +721,16 @@  discard block
 block discarded – undo
721 721
  * @param int $id
722 722
  * @return array Ids
723 723
  */
724
-		public function getIdsForNode($id) {
725
-			$subthread = $this->treeForNode($id);
726
-			$func = function (&$tree, &$entry) {
727
-				$tree['ids'][] = (int)$entry['Entry']['id'];
728
-			};
729
-			Entry::mapTreeElements($subthread, $func);
730
-			sort($subthread['ids']);
724
+        public function getIdsForNode($id) {
725
+            $subthread = $this->treeForNode($id);
726
+            $func = function (&$tree, &$entry) {
727
+                $tree['ids'][] = (int)$entry['Entry']['id'];
728
+            };
729
+            Entry::mapTreeElements($subthread, $func);
730
+            sort($subthread['ids']);
731 731
 
732
-			return $subthread['ids'];
733
-		}
732
+            return $subthread['ids'];
733
+        }
734 734
 
735 735
 /**
736 736
  * Anonymizes the entries for a user
@@ -739,24 +739,24 @@  discard block
 block discarded – undo
739 739
  *
740 740
  * @return bool success
741 741
  */
742
-		public function anonymizeEntriesFromUser($userId) {
743
-			// remove username from all entries and reassign to anonyme user
744
-			$success = $this->updateAll(
745
-				[
746
-					'Entry.name' => "NULL",
747
-					'Entry.edited_by' => "NULL",
748
-					'Entry.ip' => "NULL",
749
-					'Entry.user_id' => 0,
750
-				],
751
-				['Entry.user_id' => $userId]
752
-			);
753
-
754
-			if ($success) {
755
-				$this->_dispatchEvent('Cmd.Cache.clear', ['cache' => 'Thread']);
756
-			}
757
-
758
-			return $success;
759
-		}
742
+        public function anonymizeEntriesFromUser($userId) {
743
+            // remove username from all entries and reassign to anonyme user
744
+            $success = $this->updateAll(
745
+                [
746
+                    'Entry.name' => "NULL",
747
+                    'Entry.edited_by' => "NULL",
748
+                    'Entry.ip' => "NULL",
749
+                    'Entry.user_id' => 0,
750
+                ],
751
+                ['Entry.user_id' => $userId]
752
+            );
753
+
754
+            if ($success) {
755
+                $this->_dispatchEvent('Cmd.Cache.clear', ['cache' => 'Thread']);
756
+            }
757
+
758
+            return $success;
759
+        }
760 760
 
761 761
 /**
762 762
  * Maps all elements in $tree to function $func
@@ -768,23 +768,23 @@  discard block
 block discarded – undo
768 768
  *
769 769
  * @return string
770 770
  */
771
-		public static function mapTreeElements(&$leafs, callable $func, $context = null, &$tree = null) {
772
-			if ($tree === null) {
773
-				$tree = & $leafs;
774
-			}
775
-			foreach ($leafs as $leaf):
776
-				$result = $func($tree, $leaf, $context);
777
-				if ($result === 'break') {
778
-					return 'break';
779
-				}
780
-				if (isset($leaf['_children'])) {
781
-					$result = self::mapTreeElements($leaf['_children'], $func, $context, $tree);
782
-					if ($result === 'break') {
783
-						return 'break';
784
-					}
785
-				}
786
-			endforeach;
787
-		}
771
+        public static function mapTreeElements(&$leafs, callable $func, $context = null, &$tree = null) {
772
+            if ($tree === null) {
773
+                $tree = & $leafs;
774
+            }
775
+            foreach ($leafs as $leaf):
776
+                $result = $func($tree, $leaf, $context);
777
+                if ($result === 'break') {
778
+                    return 'break';
779
+                }
780
+                if (isset($leaf['_children'])) {
781
+                    $result = self::mapTreeElements($leaf['_children'], $func, $context, $tree);
782
+                    if ($result === 'break') {
783
+                        return 'break';
784
+                    }
785
+                }
786
+            endforeach;
787
+        }
788 788
 
789 789
 /**
790 790
  * Merge thread on to entry $targetId
@@ -792,74 +792,74 @@  discard block
 block discarded – undo
792 792
  * @param int $targetId id of the entry the thread should be appended to
793 793
  * @return bool true if merge was successfull false otherwise
794 794
  */
795
-		public function threadMerge($targetId) {
796
-			$threadIdSource = $this->id;
797
-
798
-			$this->contain();
799
-			$sourceEntry = $this->findById($threadIdSource);
800
-
801
-			// check that source is thread and not an entry
802
-			if ($sourceEntry[$this->alias]['pid'] != 0) {
803
-				return false;
804
-			}
805
-
806
-			$this->contain();
807
-			$targetEntry = $this->findById($targetId);
808
-
809
-			// check that target exists
810
-			if (!$targetEntry) {
811
-				return false;
812
-			}
813
-
814
-			// check that a thread is not merged onto itself
815
-			if ($targetEntry[$this->alias]['tid'] === $sourceEntry[$this->alias]['tid']) {
816
-				return false;
817
-			}
818
-
819
-			// set target entry as new parent entry
820
-			$this->data = [];
821
-			$this->set('pid', $targetEntry[$this->alias]['id']);
822
-			if ($this->save()) {
823
-				// associate all entries in source thread to target thread
824
-				$this->updateAll(
825
-					['tid' => $targetEntry[$this->alias]['tid']],
826
-					['tid' => $this->id]
827
-				);
828
-
829
-				// appended source entries get category of target thread
830
-				$this->_threadChangeCategory(
831
-					$targetEntry[$this->alias]['tid'],
832
-					$targetEntry[$this->alias]['category_id']
833
-				);
834
-
835
-				// update target thread last answer if source is newer
836
-				$sourceLastAnswer = $this->field('last_answer');
837
-				if (strtotime($sourceLastAnswer) > strtotime($targetEntry[$this->alias]['last_answer'])) {
838
-					$this->id = $targetEntry[$this->alias]['tid'];
839
-					$this->set('last_answer', $sourceLastAnswer);
840
-					$this->save();
841
-				}
842
-
843
-				// propagate pinned property from target to source
844
-				$isTargetPinned = (bool)$targetEntry[$this->alias]['locked'];
845
-				if ($sourceEntry[$this->alias]['locked'] !== $isTargetPinned) {
846
-					$this->id = $targetEntry[$this->alias]['tid'];
847
-					$this->_threadLock($isTargetPinned);
848
-				}
849
-
850
-				$this->Esevent->transferSubjectForEventType(
851
-					$threadIdSource,
852
-					$targetEntry[$this->alias]['tid'],
853
-					'thread'
854
-				);
855
-				$this->_dispatchEvent(
856
-					'Model.Thread.change',
857
-					['subject' => $targetEntry[$this->alias]['tid']]
858
-				);
859
-				return true;
860
-			}
861
-			return false;
862
-		}
795
+        public function threadMerge($targetId) {
796
+            $threadIdSource = $this->id;
797
+
798
+            $this->contain();
799
+            $sourceEntry = $this->findById($threadIdSource);
800
+
801
+            // check that source is thread and not an entry
802
+            if ($sourceEntry[$this->alias]['pid'] != 0) {
803
+                return false;
804
+            }
805
+
806
+            $this->contain();
807
+            $targetEntry = $this->findById($targetId);
808
+
809
+            // check that target exists
810
+            if (!$targetEntry) {
811
+                return false;
812
+            }
813
+
814
+            // check that a thread is not merged onto itself
815
+            if ($targetEntry[$this->alias]['tid'] === $sourceEntry[$this->alias]['tid']) {
816
+                return false;
817
+            }
818
+
819
+            // set target entry as new parent entry
820
+            $this->data = [];
821
+            $this->set('pid', $targetEntry[$this->alias]['id']);
822
+            if ($this->save()) {
823
+                // associate all entries in source thread to target thread
824
+                $this->updateAll(
825
+                    ['tid' => $targetEntry[$this->alias]['tid']],
826
+                    ['tid' => $this->id]
827
+                );
828
+
829
+                // appended source entries get category of target thread
830
+                $this->_threadChangeCategory(
831
+                    $targetEntry[$this->alias]['tid'],
832
+                    $targetEntry[$this->alias]['category_id']
833
+                );
834
+
835
+                // update target thread last answer if source is newer
836
+                $sourceLastAnswer = $this->field('last_answer');
837
+                if (strtotime($sourceLastAnswer) > strtotime($targetEntry[$this->alias]['last_answer'])) {
838
+                    $this->id = $targetEntry[$this->alias]['tid'];
839
+                    $this->set('last_answer', $sourceLastAnswer);
840
+                    $this->save();
841
+                }
842
+
843
+                // propagate pinned property from target to source
844
+                $isTargetPinned = (bool)$targetEntry[$this->alias]['locked'];
845
+                if ($sourceEntry[$this->alias]['locked'] !== $isTargetPinned) {
846
+                    $this->id = $targetEntry[$this->alias]['tid'];
847
+                    $this->_threadLock($isTargetPinned);
848
+                }
849
+
850
+                $this->Esevent->transferSubjectForEventType(
851
+                    $threadIdSource,
852
+                    $targetEntry[$this->alias]['tid'],
853
+                    'thread'
854
+                );
855
+                $this->_dispatchEvent(
856
+                    'Model.Thread.change',
857
+                    ['subject' => $targetEntry[$this->alias]['tid']]
858
+                );
859
+                return true;
860
+            }
861
+            return false;
862
+        }
863 863
 
864 864
 /**
865 865
  * Test if entry is thread-root
@@ -871,36 +871,36 @@  discard block
 block discarded – undo
871 871
  * @return mixed
872 872
  * @throws InvalidArgumentException
873 873
  */
874
-		public function isRoot($id = null) {
875
-			if ($id === null) {
876
-				$id = $this->id;
877
-			}
878
-
879
-			$md5 = md5(serialize($id));
880
-			if (isset($this->_isRoot[$md5]) === false) {
881
-				// $id was $entry array
882
-				if (is_array($id) && isset($id[$this->alias]['pid'])) {
883
-					$entry = $id;
884
-				} else {
885
-					if (is_array($id) && isset($id[$this->alias]['id'])) {
886
-						$id = $id[$this->alias]['id'];
887
-					} elseif (empty($id)) {
888
-						throw new InvalidArgumentException();
889
-					}
890
-					$entry = $this->find(
891
-						'first',
892
-						array(
893
-							'contain' => false,
894
-							'conditions' => array(
895
-								'id' => $id,
896
-							)
897
-						)
898
-					);
899
-				}
900
-				$this->_isRoot[$md5] = empty($entry[$this->alias]['pid']);
901
-			}
902
-			return $this->_isRoot[$md5];
903
-		}
874
+        public function isRoot($id = null) {
875
+            if ($id === null) {
876
+                $id = $this->id;
877
+            }
878
+
879
+            $md5 = md5(serialize($id));
880
+            if (isset($this->_isRoot[$md5]) === false) {
881
+                // $id was $entry array
882
+                if (is_array($id) && isset($id[$this->alias]['pid'])) {
883
+                    $entry = $id;
884
+                } else {
885
+                    if (is_array($id) && isset($id[$this->alias]['id'])) {
886
+                        $id = $id[$this->alias]['id'];
887
+                    } elseif (empty($id)) {
888
+                        throw new InvalidArgumentException();
889
+                    }
890
+                    $entry = $this->find(
891
+                        'first',
892
+                        array(
893
+                            'contain' => false,
894
+                            'conditions' => array(
895
+                                'id' => $id,
896
+                            )
897
+                        )
898
+                    );
899
+                }
900
+                $this->_isRoot[$md5] = empty($entry[$this->alias]['pid']);
901
+            }
902
+            return $this->_isRoot[$md5];
903
+        }
904 904
 
905 905
 /**
906 906
  * Preprocesses entry data before saving it
@@ -911,85 +911,85 @@  discard block
 block discarded – undo
911 911
  * @throws InvalidArgumentException
912 912
  * @throws ForbiddenException
913 913
  */
914
-		public function prepare(&$data, array $options = []) {
915
-			$options += [
916
-				'isRoot' => null
917
-			];
918
-
919
-			if (isset($options['preFilterFields'])) {
920
-				$org = $data;
921
-				$this->filterFields($data, $options['preFilterFields']);
922
-				if (isset($org['Event'])) {
923
-					$data['Event'] = $org['Event'];
924
-				}
925
-			}
926
-			unset($options['preFilterFields']);
927
-
928
-			$isRoot = $options['isRoot'];
929
-			unset($options['isRoot']);
930
-
931
-			if ($isRoot === null) {
932
-				$isRoot = $this->isRoot($data);
933
-			}
934
-			// adds info from parent entry to an answer
935
-			if ($isRoot === false) {
936
-				if (!isset($data[$this->alias]['pid'])) {
937
-					$pid = $this->getParentId($data[$this->alias]['id']);
938
-				} else {
939
-					$pid = $data[$this->alias]['pid'];
940
-				}
941
-				$parent = $this->get($pid, true);
942
-				if ($parent === false) {
943
-					throw new InvalidArgumentException;
944
-				}
945
-
946
-				// @todo highly @bogus should be a validator?
947
-				$parentPosting = $this->dic->newInstance('\Saito\Posting\Posting', ['rawData' => $parent]);
948
-				if ($parentPosting->isAnsweringForbidden()) {
949
-					throw new ForbiddenException;
950
-				}
951
-
952
-				// if new subject is empty use the parent's subject
953
-				if (empty($data[$this->alias]['subject'])) {
954
-					$data[$this->alias]['subject'] = $parent[$this->alias]['subject'];
955
-				}
956
-
957
-				$data[$this->alias]['tid'] = $parent[$this->alias]['tid'];
958
-				$data[$this->alias]['category_id'] = $parent[$this->alias]['category_id'];
959
-			}
960
-
961
-			//= markup preprocessing
962
-			if (empty($data[$this->alias]['text']) === false) {
963
-				$data[$this->alias]['text'] = $this->prepareMarkup($data[$this->alias]['text']);
964
-			}
965
-		}
966
-
967
-		protected function _findEntry($state, $query, $results = []) {
968
-			if ($state === 'before') {
969
-				$query['contain'] = ['User', 'Category'];
970
-				$query['fields'] = array_merge($this->threadLineFieldList, $this->showEntryFieldListAdditional);
971
-				return $query;
972
-			}
973
-			if ($results) {
974
-				return $results[0];
975
-			}
976
-			return $results;
977
-		}
914
+        public function prepare(&$data, array $options = []) {
915
+            $options += [
916
+                'isRoot' => null
917
+            ];
918
+
919
+            if (isset($options['preFilterFields'])) {
920
+                $org = $data;
921
+                $this->filterFields($data, $options['preFilterFields']);
922
+                if (isset($org['Event'])) {
923
+                    $data['Event'] = $org['Event'];
924
+                }
925
+            }
926
+            unset($options['preFilterFields']);
927
+
928
+            $isRoot = $options['isRoot'];
929
+            unset($options['isRoot']);
930
+
931
+            if ($isRoot === null) {
932
+                $isRoot = $this->isRoot($data);
933
+            }
934
+            // adds info from parent entry to an answer
935
+            if ($isRoot === false) {
936
+                if (!isset($data[$this->alias]['pid'])) {
937
+                    $pid = $this->getParentId($data[$this->alias]['id']);
938
+                } else {
939
+                    $pid = $data[$this->alias]['pid'];
940
+                }
941
+                $parent = $this->get($pid, true);
942
+                if ($parent === false) {
943
+                    throw new InvalidArgumentException;
944
+                }
945
+
946
+                // @todo highly @bogus should be a validator?
947
+                $parentPosting = $this->dic->newInstance('\Saito\Posting\Posting', ['rawData' => $parent]);
948
+                if ($parentPosting->isAnsweringForbidden()) {
949
+                    throw new ForbiddenException;
950
+                }
951
+
952
+                // if new subject is empty use the parent's subject
953
+                if (empty($data[$this->alias]['subject'])) {
954
+                    $data[$this->alias]['subject'] = $parent[$this->alias]['subject'];
955
+                }
956
+
957
+                $data[$this->alias]['tid'] = $parent[$this->alias]['tid'];
958
+                $data[$this->alias]['category_id'] = $parent[$this->alias]['category_id'];
959
+            }
960
+
961
+            //= markup preprocessing
962
+            if (empty($data[$this->alias]['text']) === false) {
963
+                $data[$this->alias]['text'] = $this->prepareMarkup($data[$this->alias]['text']);
964
+            }
965
+        }
966
+
967
+        protected function _findEntry($state, $query, $results = []) {
968
+            if ($state === 'before') {
969
+                $query['contain'] = ['User', 'Category'];
970
+                $query['fields'] = array_merge($this->threadLineFieldList, $this->showEntryFieldListAdditional);
971
+                return $query;
972
+            }
973
+            if ($results) {
974
+                return $results[0];
975
+            }
976
+            return $results;
977
+        }
978 978
 
979 979
 /**
980 980
  * Implements the custom find type 'feed'
981 981
  *
982 982
  * Add parameters for generating a rss/json-feed with find('feed', …)
983 983
  */
984
-		protected function _findFeed($state, $query, $results = array()) {
985
-			if ($state == 'before') {
986
-				$query['contain'] = array('User');
987
-				$query['fields'] = $this->_allowedPublicOutputFields;
988
-				$query['limit'] = 10;
989
-				return $query;
990
-			}
991
-			return $results;
992
-		}
984
+        protected function _findFeed($state, $query, $results = array()) {
985
+            if ($state == 'before') {
986
+                $query['contain'] = array('User');
987
+                $query['fields'] = $this->_allowedPublicOutputFields;
988
+                $query['limit'] = 10;
989
+                return $query;
990
+            }
991
+            return $results;
992
+        }
993 993
 
994 994
 /**
995 995
  * Locks or unlocks a whole thread
@@ -998,57 +998,57 @@  discard block
 block discarded – undo
998 998
  *
999 999
  * @param bool $value
1000 1000
  */
1001
-		protected function _threadLock($value) {
1002
-			$tid = $this->field('tid');
1003
-			$this->contain();
1004
-			// @bogus throws error on $value = false
1005
-			$value = $value ? 1 : 0;
1006
-			$this->updateAll(['locked' => $value], ['tid' => $tid]);
1007
-		}
1008
-
1009
-		public function paginateCount($conditions, $recursive, $extra) {
1010
-			if (isset($extra['getInitialThreads'])) {
1011
-				$this->Category->contain();
1012
-				$categories = $this->Category->find(
1013
-					'all',
1014
-					[
1015
-						'conditions' => array('id' => $conditions['Entry.category_id']),
1016
-						'fields' => array('thread_count')
1017
-					]
1018
-				);
1019
-				$count = array_sum(Set::extract('/Category/thread_count', $categories));
1020
-			} else {
1021
-				$parameters = array('conditions' => $conditions);
1022
-				if ($recursive != $this->recursive) {
1023
-					$parameters['recursive'] = $recursive;
1024
-				}
1025
-				$count = $this->find('count', array_merge($parameters, $extra));
1026
-			}
1027
-			return $count;
1028
-		}
1029
-
1030
-		public function beforeSave($options = array()) {
1031
-			$success = true;
1032
-
1033
-			//# change category of thread if category of root entry changed
1034
-			$modified = !empty($this->id);
1035
-			if (isset($this->data[$this->alias]['category_id']) && $modified) {
1036
-				$oldEntry = $this->find('first',
1037
-					['contain' => false, 'conditions' => ['Entry.id' => $this->id]]);
1038
-
1039
-				if ($oldEntry && (int)$oldEntry[$this->alias]['pid'] === 0) {
1040
-					$categoryChanged = (int)$this->data[$this->alias]['category_id'] !== (int)$oldEntry[$this->alias]['category_id'];
1041
-					if ($categoryChanged) {
1042
-						$success = $success && $this->_threadChangeCategory(
1043
-								$oldEntry[$this->alias]['tid'],
1044
-								$this->data[$this->alias]['category_id']
1045
-							);
1046
-					}
1047
-				}
1048
-			}
1049
-
1050
-			return $success && parent::beforeSave($options);
1051
-		}
1001
+        protected function _threadLock($value) {
1002
+            $tid = $this->field('tid');
1003
+            $this->contain();
1004
+            // @bogus throws error on $value = false
1005
+            $value = $value ? 1 : 0;
1006
+            $this->updateAll(['locked' => $value], ['tid' => $tid]);
1007
+        }
1008
+
1009
+        public function paginateCount($conditions, $recursive, $extra) {
1010
+            if (isset($extra['getInitialThreads'])) {
1011
+                $this->Category->contain();
1012
+                $categories = $this->Category->find(
1013
+                    'all',
1014
+                    [
1015
+                        'conditions' => array('id' => $conditions['Entry.category_id']),
1016
+                        'fields' => array('thread_count')
1017
+                    ]
1018
+                );
1019
+                $count = array_sum(Set::extract('/Category/thread_count', $categories));
1020
+            } else {
1021
+                $parameters = array('conditions' => $conditions);
1022
+                if ($recursive != $this->recursive) {
1023
+                    $parameters['recursive'] = $recursive;
1024
+                }
1025
+                $count = $this->find('count', array_merge($parameters, $extra));
1026
+            }
1027
+            return $count;
1028
+        }
1029
+
1030
+        public function beforeSave($options = array()) {
1031
+            $success = true;
1032
+
1033
+            //# change category of thread if category of root entry changed
1034
+            $modified = !empty($this->id);
1035
+            if (isset($this->data[$this->alias]['category_id']) && $modified) {
1036
+                $oldEntry = $this->find('first',
1037
+                    ['contain' => false, 'conditions' => ['Entry.id' => $this->id]]);
1038
+
1039
+                if ($oldEntry && (int)$oldEntry[$this->alias]['pid'] === 0) {
1040
+                    $categoryChanged = (int)$this->data[$this->alias]['category_id'] !== (int)$oldEntry[$this->alias]['category_id'];
1041
+                    if ($categoryChanged) {
1042
+                        $success = $success && $this->_threadChangeCategory(
1043
+                                $oldEntry[$this->alias]['tid'],
1044
+                                $this->data[$this->alias]['category_id']
1045
+                            );
1046
+                    }
1047
+                }
1048
+            }
1049
+
1050
+            return $success && parent::beforeSave($options);
1051
+        }
1052 1052
 
1053 1053
 /**
1054 1054
  * check that entries are only in existing and allowed categories
@@ -1056,35 +1056,35 @@  discard block
 block discarded – undo
1056 1056
  * @param $check
1057 1057
  * @return bool
1058 1058
  */
1059
-		public function validateCategoryIsAllowed($check) {
1060
-			$availableCategories = $this->CurrentUser->Categories->getAllowed();
1061
-			if (!isset($availableCategories[$check['category_id']])) {
1062
-				return false;
1063
-			}
1064
-			return true;
1065
-		}
1066
-
1067
-		/**
1068
-		 * @param $check
1069
-		 * @return bool
1070
-		 * @throws Exception
1071
-		 */
1072
-		public function validateEditingAllowed($check) {
1073
-			$id = $this->data[$this->alias]['id'];
1074
-			$entry = $this->get($id);
1075
-			if (empty($entry)) {
1076
-				throw new Exception(sprintf('Entry %s not found.', $entry));
1077
-			}
1078
-
1079
-			$posting = $this->dic->newInstance('\Saito\Posting\Posting', ['rawData' => $entry]);
1080
-			$forbidden = $posting->isEditingAsCurrentUserForbidden();
1081
-
1082
-			if (is_bool($forbidden)) {
1083
-				return !$forbidden;
1084
-			} else {
1085
-				return $forbidden;
1086
-			}
1087
-		}
1059
+        public function validateCategoryIsAllowed($check) {
1060
+            $availableCategories = $this->CurrentUser->Categories->getAllowed();
1061
+            if (!isset($availableCategories[$check['category_id']])) {
1062
+                return false;
1063
+            }
1064
+            return true;
1065
+        }
1066
+
1067
+        /**
1068
+         * @param $check
1069
+         * @return bool
1070
+         * @throws Exception
1071
+         */
1072
+        public function validateEditingAllowed($check) {
1073
+            $id = $this->data[$this->alias]['id'];
1074
+            $entry = $this->get($id);
1075
+            if (empty($entry)) {
1076
+                throw new Exception(sprintf('Entry %s not found.', $entry));
1077
+            }
1078
+
1079
+            $posting = $this->dic->newInstance('\Saito\Posting\Posting', ['rawData' => $entry]);
1080
+            $forbidden = $posting->isEditingAsCurrentUserForbidden();
1081
+
1082
+            if (is_bool($forbidden)) {
1083
+                return !$forbidden;
1084
+            } else {
1085
+                return $forbidden;
1086
+            }
1087
+        }
1088 1088
 
1089 1089
 /**
1090 1090
  *
@@ -1097,9 +1097,9 @@  discard block
 block discarded – undo
1097 1097
  * @param $check
1098 1098
  * @return bool
1099 1099
  */
1100
-		public function validateSubjectMaxLength($check) {
1101
-			return mb_strlen($check['subject']) <= $this->_setting('subject_maxlength');
1102
-		}
1100
+        public function validateSubjectMaxLength($check) {
1101
+            return mb_strlen($check['subject']) <= $this->_setting('subject_maxlength');
1102
+        }
1103 1103
 
1104 1104
 /**
1105 1105
  * Changes the category of a thread.
@@ -1113,20 +1113,20 @@  discard block
 block discarded – undo
1113 1113
  * @throws NotFoundException
1114 1114
  * @throws InvalidArgumentException
1115 1115
  */
1116
-		protected function _threadChangeCategory($tid = null, $newCategoryId = null) {
1117
-			if (empty($tid)) {
1118
-				throw new InvalidArgumentException;
1119
-			}
1120
-			$this->Category->contain();
1121
-			$categoryExists = $this->Category->findById($newCategoryId);
1122
-			if (!$categoryExists) {
1123
-				throw new NotFoundException;
1124
-			}
1125
-			$out = $this->updateAll(
1126
-				['Entry.category_id' => $newCategoryId],
1127
-				['Entry.tid' => $tid]
1128
-			);
1129
-			return $out;
1130
-		}
1131
-
1132
-	}
1133 1116
\ No newline at end of file
1117
+        protected function _threadChangeCategory($tid = null, $newCategoryId = null) {
1118
+            if (empty($tid)) {
1119
+                throw new InvalidArgumentException;
1120
+            }
1121
+            $this->Category->contain();
1122
+            $categoryExists = $this->Category->findById($newCategoryId);
1123
+            if (!$categoryExists) {
1124
+                throw new NotFoundException;
1125
+            }
1126
+            $out = $this->updateAll(
1127
+                ['Entry.category_id' => $newCategoryId],
1128
+                ['Entry.tid' => $tid]
1129
+            );
1130
+            return $out;
1131
+        }
1132
+
1133
+    }
1134 1134
\ No newline at end of file
Please login to merge, or discard this patch.
app/Model/Esnotification.php 1 patch
Indentation   +29 added lines, -29 removed lines patch added patch discarded remove patch
@@ -8,43 +8,43 @@
 block discarded – undo
8 8
  */
9 9
 class Esnotification extends AppModel {
10 10
 
11
-	//The Associations below have been created with all possible keys, those that are not needed can be removed
11
+    //The Associations below have been created with all possible keys, those that are not needed can be removed
12 12
 
13 13
 /**
14 14
  * belongsTo associations
15 15
  *
16 16
  * @var array
17 17
  */
18
-	public $belongsTo = array(
19
-		'User' => array(
20
-			'className' => 'User',
21
-			'foreignKey' => 'user_id',
22
-			'conditions' => '',
23
-			'fields' => '',
24
-			'order' => ''
25
-		),
26
-		'Esevent' => array(
27
-			'className' => 'Esevent',
28
-			'foreignKey' => 'esevent_id',
29
-			'conditions' => '',
30
-			'fields' => '',
31
-			'order' => ''
32
-		)
33
-	);
18
+    public $belongsTo = array(
19
+        'User' => array(
20
+            'className' => 'User',
21
+            'foreignKey' => 'user_id',
22
+            'conditions' => '',
23
+            'fields' => '',
24
+            'order' => ''
25
+        ),
26
+        'Esevent' => array(
27
+            'className' => 'Esevent',
28
+            'foreignKey' => 'esevent_id',
29
+            'conditions' => '',
30
+            'fields' => '',
31
+            'order' => ''
32
+        )
33
+    );
34 34
 
35
-	public function beforeSave($options = array()) {
36
-		if (empty($this->data[$this->alias]['deactivate'])) {
37
-			$this->data[$this->alias]['deactivate'] = mt_rand(0, 99999999);
38
-		}
35
+    public function beforeSave($options = array()) {
36
+        if (empty($this->data[$this->alias]['deactivate'])) {
37
+            $this->data[$this->alias]['deactivate'] = mt_rand(0, 99999999);
38
+        }
39 39
 
40
-		return parent::beforeSave();
41
-	}
40
+        return parent::beforeSave();
41
+    }
42 42
 
43
-	public function deleteNotificationWithId($id) {
44
-			return $this->delete($id, false);
45
-	}
43
+    public function deleteNotificationWithId($id) {
44
+            return $this->delete($id, false);
45
+    }
46 46
 
47
-	public function deleteAllFromUser($userId) {
48
-		return $this->deleteAll(array('user_id' => $userId), false);
49
-	}
47
+    public function deleteAllFromUser($userId) {
48
+        return $this->deleteAll(array('user_id' => $userId), false);
49
+    }
50 50
 }
Please login to merge, or discard this patch.
app/Model/Behavior/TreeBehavior.php 1 patch
Indentation   +52 added lines, -52 removed lines patch added patch discarded remove patch
@@ -1,35 +1,35 @@  discard block
 block discarded – undo
1 1
 <?php
2 2
 
3
-	class TreeBehavior extends ModelBehavior {
4
-
5
-		public function treeGetSubtree(Model $Model, $tree, $_nodeId) {
6
-			$func = function (&$tree, &$entry, $_nodeId) {
7
-				if ((int)$entry['Entry']['id'] === (int)$_nodeId) {
8
-					$tree = array($entry);
9
-					return 'break';
10
-				}
11
-			};
12
-			Entry::mapTreeElements($tree, $func, $_nodeId);
13
-			return $tree;
14
-		}
15
-
16
-		public function treeBuild(Model $Model, $threads) {
17
-			$tree = array();
18
-			foreach ($threads as $thread) {
19
-				$id = $thread[$Model->alias]['id'];
20
-				$pid = $thread[$Model->alias]['pid'];
21
-				$tree[$id] = isset($tree[$id]) ? $tree[$id] + $thread : $thread;
22
-				$tree[$pid]['_children'][] = &$tree[$id];
23
-			}
24
-
25
-			// It's possible to do uasort before tree build and  get the same results,
26
-			// without _sortTreesAfterTime
27
-			// but then *all* entries have to be sorted whereas now only subthreads with childs
28
-			// are sorted. So using _sortTreesAfterTime is actually faster in praxis.
29
-			$_sortedTrees = $this->_sortTreesAfterTime($tree[0]['_children']);
30
-
31
-			return $_sortedTrees;
32
-		}
3
+    class TreeBehavior extends ModelBehavior {
4
+
5
+        public function treeGetSubtree(Model $Model, $tree, $_nodeId) {
6
+            $func = function (&$tree, &$entry, $_nodeId) {
7
+                if ((int)$entry['Entry']['id'] === (int)$_nodeId) {
8
+                    $tree = array($entry);
9
+                    return 'break';
10
+                }
11
+            };
12
+            Entry::mapTreeElements($tree, $func, $_nodeId);
13
+            return $tree;
14
+        }
15
+
16
+        public function treeBuild(Model $Model, $threads) {
17
+            $tree = array();
18
+            foreach ($threads as $thread) {
19
+                $id = $thread[$Model->alias]['id'];
20
+                $pid = $thread[$Model->alias]['pid'];
21
+                $tree[$id] = isset($tree[$id]) ? $tree[$id] + $thread : $thread;
22
+                $tree[$pid]['_children'][] = &$tree[$id];
23
+            }
24
+
25
+            // It's possible to do uasort before tree build and  get the same results,
26
+            // without _sortTreesAfterTime
27
+            // but then *all* entries have to be sorted whereas now only subthreads with childs
28
+            // are sorted. So using _sortTreesAfterTime is actually faster in praxis.
29
+            $_sortedTrees = $this->_sortTreesAfterTime($tree[0]['_children']);
30
+
31
+            return $_sortedTrees;
32
+        }
33 33
 
34 34
 /**
35 35
  * Sort all entries in trees after time
@@ -38,25 +38,25 @@  discard block
 block discarded – undo
38 38
  * @param int $level
39 39
  * @return array
40 40
  */
41
-		protected function _sortTreesAfterTime($in, $level = 0) {
42
-			if ($level > 0) {
43
-				uasort($in, [$this, '_sort']);
44
-			}
45
-
46
-			foreach ($in as $k => $v) {
47
-				if (isset($v['_children'])) {
48
-					$in[$k]['_children'] = $this->_sortTreesAfterTime($v['_children'], $level + 1);
49
-				}
50
-			}
51
-			return $in;
52
-		}
53
-
54
-		protected function _sort($a, $b) {
55
-			if ($a['Entry']['time'] === $b['Entry']['time']) {
56
-				return ($a['Entry']['id'] > $b['Entry']['id']) ? 1 : -1;
57
-			} else {
58
-				return ($a['Entry']['time'] > $b['Entry']['time']) ? 1 : -1;
59
-			}
60
-		}
61
-
62
-	}
41
+        protected function _sortTreesAfterTime($in, $level = 0) {
42
+            if ($level > 0) {
43
+                uasort($in, [$this, '_sort']);
44
+            }
45
+
46
+            foreach ($in as $k => $v) {
47
+                if (isset($v['_children'])) {
48
+                    $in[$k]['_children'] = $this->_sortTreesAfterTime($v['_children'], $level + 1);
49
+                }
50
+            }
51
+            return $in;
52
+        }
53
+
54
+        protected function _sort($a, $b) {
55
+            if ($a['Entry']['time'] === $b['Entry']['time']) {
56
+                return ($a['Entry']['id'] > $b['Entry']['id']) ? 1 : -1;
57
+            } else {
58
+                return ($a['Entry']['time'] > $b['Entry']['time']) ? 1 : -1;
59
+            }
60
+        }
61
+
62
+    }
Please login to merge, or discard this patch.
app/Model/Behavior/MarkupBehavior.php 1 patch
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -1,35 +1,35 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-	App::uses('ModelBehavior', 'Model');
3
+    App::uses('ModelBehavior', 'Model');
4 4
 
5
-	class MarkupBehavior extends ModelBehavior {
5
+    class MarkupBehavior extends ModelBehavior {
6 6
 
7
-		/**
8
-		 * @var Saito\Markup\Preprocessor
9
-		 */
10
-		protected $_Preprocessor;
7
+        /**
8
+         * @var Saito\Markup\Preprocessor
9
+         */
10
+        protected $_Preprocessor;
11 11
 
12
-		/**
13
-		 * @param Model $Model
14
-		 * @param $string
15
-		 * @return string
16
-		 */
17
-		public function prepareMarkup(Model $Model, $string) {
18
-			if (empty($string)) {
19
-				return $string;
20
-			}
21
-			return $this->_getPreprocessor()->process($string);
22
-		}
12
+        /**
13
+         * @param Model $Model
14
+         * @param $string
15
+         * @return string
16
+         */
17
+        public function prepareMarkup(Model $Model, $string) {
18
+            if (empty($string)) {
19
+                return $string;
20
+            }
21
+            return $this->_getPreprocessor()->process($string);
22
+        }
23 23
 
24
-		protected function _getPreprocessor() {
25
-			if ($this->_Preprocessor === null) {
26
-				$settings = Configure::read('Saito.Settings.Parser');
27
-				$this->_Preprocessor = \Saito\Plugin::getParserClassInstance(
28
-					'Preprocessor',
29
-					$settings
30
-				);
31
-			}
32
-			return $this->_Preprocessor;
33
-		}
24
+        protected function _getPreprocessor() {
25
+            if ($this->_Preprocessor === null) {
26
+                $settings = Configure::read('Saito.Settings.Parser');
27
+                $this->_Preprocessor = \Saito\Plugin::getParserClassInstance(
28
+                    'Preprocessor',
29
+                    $settings
30
+                );
31
+            }
32
+            return $this->_Preprocessor;
33
+        }
34 34
 
35
-	}
35
+    }
Please login to merge, or discard this patch.
app/Model/Upload.php 1 patch
Indentation   +23 added lines, -23 removed lines patch added patch discarded remove patch
@@ -7,24 +7,24 @@  discard block
 block discarded – undo
7 7
  */
8 8
 class Upload extends AppModel {
9 9
 
10
-	public $name = 'Upload';
10
+    public $name = 'Upload';
11 11
 
12
-	public $recursive = -1;
12
+    public $recursive = -1;
13 13
 
14
-	public $actsAs = array('FileUpload.FileUpload');
14
+    public $actsAs = array('FileUpload.FileUpload');
15 15
 
16
-	public $belongsTo = array('User');
16
+    public $belongsTo = array('User');
17 17
 
18
-	public function deleteAllFromUser($userId) {
19
-		return $this->deleteAll(
20
-			array(
21
-				'Upload.user_id' => $userId
22
-			),
23
-			false,
24
-			// call beforeDelete FileUploader plugin callback to remove files from disk
25
-			true
26
-		);
27
-	}
18
+    public function deleteAllFromUser($userId) {
19
+        return $this->deleteAll(
20
+            array(
21
+                'Upload.user_id' => $userId
22
+            ),
23
+            false,
24
+            // call beforeDelete FileUploader plugin callback to remove files from disk
25
+            true
26
+        );
27
+    }
28 28
 
29 29
 /**
30 30
  * Returns the number of uploads a user `user_id` has made
@@ -33,14 +33,14 @@  discard block
 block discarded – undo
33 33
  *
34 34
  * @return int
35 35
  */
36
-	public function countUser($userId) {
37
-		$number = $this->find(
38
-			'count',
39
-			array(
40
-				'conditions' => array('user_id' => $userId)
41
-			)
42
-		);
43
-		return (int)$number;
44
-	}
36
+    public function countUser($userId) {
37
+        $number = $this->find(
38
+            'count',
39
+            array(
40
+                'conditions' => array('user_id' => $userId)
41
+            )
42
+        );
43
+        return (int)$number;
44
+    }
45 45
 
46 46
 }
47 47
\ No newline at end of file
Please login to merge, or discard this patch.
app/Model/AppModel.php 1 patch
Indentation   +261 added lines, -261 removed lines patch added patch discarded remove patch
@@ -1,291 +1,291 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-	App::uses('Model', 'Model');
4
-	App::uses('Sanitize', 'Utility');
5
-	App::uses('CakeEvent', 'Event');
6
-	App::uses('SaitoEventManager', 'Lib/Saito/Event');
3
+    App::uses('Model', 'Model');
4
+    App::uses('Sanitize', 'Utility');
5
+    App::uses('CakeEvent', 'Event');
6
+    App::uses('SaitoEventManager', 'Lib/Saito/Event');
7 7
 
8
-	// import here so that `cake schema ...` cli works
9
-	App::import('Lib', 'Stopwatch.Stopwatch');
8
+    // import here so that `cake schema ...` cli works
9
+    App::import('Lib', 'Stopwatch.Stopwatch');
10 10
 
11
-	class AppModel extends Model {
11
+    class AppModel extends Model {
12 12
 
13
-		/**
14
-		 * @var array model settings; can be overwritten by DB or config Settings
15
-		 */
16
-		protected $_settings = [];
13
+        /**
14
+         * @var array model settings; can be overwritten by DB or config Settings
15
+         */
16
+        protected $_settings = [];
17 17
 
18
-		/**
19
-		 * @var array predefined fields for filterFields()
20
-		 */
21
-		public $allowedInputFields = [];
18
+        /**
19
+         * @var array predefined fields for filterFields()
20
+         */
21
+        public $allowedInputFields = [];
22 22
 
23
-		# Entry->User->UserOnline
24
-		public $recursive = 1;
23
+        # Entry->User->UserOnline
24
+        public $recursive = 1;
25 25
 
26
-		public $SharedObjects;
26
+        public $SharedObjects;
27 27
 
28
-		/** * @var SaitoEventManager */
29
-		protected $_SEM;
28
+        /** * @var SaitoEventManager */
29
+        protected $_SEM;
30 30
 
31
-		public function __construct($id = false, $table = null, $ds = null) {
32
-			parent::__construct($id, $table, $ds);
33
-			$this->_dispatchEvent('Event.Saito.Model.initialize');
34
-		}
31
+        public function __construct($id = false, $table = null, $ds = null) {
32
+            parent::__construct($id, $table, $ds);
33
+            $this->_dispatchEvent('Event.Saito.Model.initialize');
34
+        }
35 35
 
36
-		public function __get($name) {
37
-			switch ($name) {
38
-				case 'dic':
39
-					return ClassRegistry::getObject('dic');
40
-				default:
41
-					if (isset($this->SharedObjects[$name])) {
42
-						return $this->SharedObjects[$name];
43
-					}
44
-			}
45
-			return parent::__get($name);
46
-		}
36
+        public function __get($name) {
37
+            switch ($name) {
38
+                case 'dic':
39
+                    return ClassRegistry::getObject('dic');
40
+                default:
41
+                    if (isset($this->SharedObjects[$name])) {
42
+                        return $this->SharedObjects[$name];
43
+                    }
44
+            }
45
+            return parent::__get($name);
46
+        }
47 47
 
48
-		public function toggle($key) {
49
-			$this->contain();
50
-			$value = $this->read($key);
51
-			$value = ($value[$this->alias][$key] == 0) ? 1 : 0;
52
-			$this->set($key, $value);
53
-			$this->save();
54
-			return $value;
55
-		}
48
+        public function toggle($key) {
49
+            $this->contain();
50
+            $value = $this->read($key);
51
+            $value = ($value[$this->alias][$key] == 0) ? 1 : 0;
52
+            $this->set($key, $value);
53
+            $this->save();
54
+            return $value;
55
+        }
56 56
 
57
-		/**
58
-		 * filters out all fields $fields in $data
59
-		 *
60
-		 * works only on current model, not associations
61
-		 *
62
-		 * @param $data
63
-		 * @param $fields
64
-		 */
65
-		public function filterFields(&$data, $fields) {
66
-			if (is_string($fields) && isset($this->allowedInputFields[$fields])) {
67
-				$fields = $this->allowedInputFields[$fields];
68
-			}
69
-			$fields = array_flip($fields);
70
-			$data = [
71
-				$this->alias => array_intersect_key($data[$this->alias], $fields)
72
-			];
73
-		}
57
+        /**
58
+         * filters out all fields $fields in $data
59
+         *
60
+         * works only on current model, not associations
61
+         *
62
+         * @param $data
63
+         * @param $fields
64
+         */
65
+        public function filterFields(&$data, $fields) {
66
+            if (is_string($fields) && isset($this->allowedInputFields[$fields])) {
67
+                $fields = $this->allowedInputFields[$fields];
68
+            }
69
+            $fields = array_flip($fields);
70
+            $data = [
71
+                $this->alias => array_intersect_key($data[$this->alias], $fields)
72
+            ];
73
+        }
74 74
 
75
-		public function requireFields(&$data, array $required) {
76
-			return $this->_mapFields($data, $required,
77
-				function (&$data, $model, $field) {
78
-					if (!isset($data[$model][$field])) {
79
-						return false;
80
-					}
81
-					return true;
82
-				});
83
-		}
75
+        public function requireFields(&$data, array $required) {
76
+            return $this->_mapFields($data, $required,
77
+                function (&$data, $model, $field) {
78
+                    if (!isset($data[$model][$field])) {
79
+                        return false;
80
+                    }
81
+                    return true;
82
+                });
83
+        }
84 84
 
85
-		public function unsetFields(&$data, array $unset = ['id']) {
86
-			return $this->_mapFields($data, $unset,
87
-				function (&$data, $model, $field) {
88
-					if (isset($data[$model][$field])) {
89
-						unset($data[$model][$field]);
90
-					}
91
-					return true;
92
-				});
93
-		}
85
+        public function unsetFields(&$data, array $unset = ['id']) {
86
+            return $this->_mapFields($data, $unset,
87
+                function (&$data, $model, $field) {
88
+                    if (isset($data[$model][$field])) {
89
+                        unset($data[$model][$field]);
90
+                    }
91
+                    return true;
92
+                });
93
+        }
94 94
 
95
-		protected function _mapFields(&$data, $fields, callable $func) {
96
-			if (isset(reset($data)[$this->alias])) {
97
-				foreach ($data as &$d) {
98
-					if (!$this->_mapFields($d, $fields, $func)) {
99
-						return false;
100
-					}
101
-				}
102
-				return true;
103
-			}
95
+        protected function _mapFields(&$data, $fields, callable $func) {
96
+            if (isset(reset($data)[$this->alias])) {
97
+                foreach ($data as &$d) {
98
+                    if (!$this->_mapFields($d, $fields, $func)) {
99
+                        return false;
100
+                    }
101
+                }
102
+                return true;
103
+            }
104 104
 
105
-			if (!isset($data[$this->alias])) {
106
-				$data = [$this->alias => $data];
107
-			}
108
-			foreach ($fields as $field) {
109
-				if (strpos($field, '.') !== false) {
110
-					list($model, $field) = explode('.', $field, 2);
111
-				} else {
112
-					$model = $this->alias;
113
-				}
114
-				if ($model !== $this->alias) {
115
-					continue;
116
-				}
117
-				if (!$func($data, $model, $field)) {
118
-					return false;
119
-				}
120
-			}
121
-			return true;
122
-		}
105
+            if (!isset($data[$this->alias])) {
106
+                $data = [$this->alias => $data];
107
+            }
108
+            foreach ($fields as $field) {
109
+                if (strpos($field, '.') !== false) {
110
+                    list($model, $field) = explode('.', $field, 2);
111
+                } else {
112
+                    $model = $this->alias;
113
+                }
114
+                if ($model !== $this->alias) {
115
+                    continue;
116
+                }
117
+                if (!$func($data, $model, $field)) {
118
+                    return false;
119
+                }
120
+            }
121
+            return true;
122
+        }
123 123
 
124
-		/**
125
-		 * Increments value of a field
126
-		 *
127
-		 * @param $id
128
-		 * @param $field
129
-		 * @param int $amount
130
-		 * @throws InvalidArgumentException
131
-		 */
132
-		public function increment($id, $field, $amount = 1) {
133
-			if (!is_int($amount)) {
134
-				throw new InvalidArgumentException;
135
-			}
136
-			$operator = '+';
137
-			if ($amount < 0) {
138
-				$operator = '-';
139
-				$amount *= -1;
140
-			}
141
-			$field = $this->alias . '.' . $field;
142
-			$this->updateAll([$field => "$field $operator $amount"],
143
-				[$this->alias . '.id' => $id]);
144
-		}
124
+        /**
125
+         * Increments value of a field
126
+         *
127
+         * @param $id
128
+         * @param $field
129
+         * @param int $amount
130
+         * @throws InvalidArgumentException
131
+         */
132
+        public function increment($id, $field, $amount = 1) {
133
+            if (!is_int($amount)) {
134
+                throw new InvalidArgumentException;
135
+            }
136
+            $operator = '+';
137
+            if ($amount < 0) {
138
+                $operator = '-';
139
+                $amount *= -1;
140
+            }
141
+            $field = $this->alias . '.' . $field;
142
+            $this->updateAll([$field => "$field $operator $amount"],
143
+                [$this->alias . '.id' => $id]);
144
+        }
145 145
 
146
-		public function pipeMerger(array $data) {
147
-			$out = [];
148
-			foreach ($data as $key => $value) {
149
-				$out[] = "$key=$value";
150
-			}
151
-			return implode(' | ', $out);
152
-		}
146
+        public function pipeMerger(array $data) {
147
+            $out = [];
148
+            foreach ($data as $key => $value) {
149
+                $out[] = "$key=$value";
150
+            }
151
+            return implode(' | ', $out);
152
+        }
153 153
 
154
-		/**
155
-		 * Splits String 'a=b|c=d|e=f' into an array('a'=>'b', 'c'=>'d', 'e'=>'f')
156
-		 *
157
-		 * @param string $pipeString
158
-		 * @return array
159
-		 */
160
-		protected function _pipeSplitter($pipeString) {
161
-			$unpipedArray = array();
162
-			$ranks = explode('|', $pipeString);
163
-			foreach ($ranks as $rank) :
164
-				$matches = array();
165
-				$matched = preg_match('/(\w+)\s*=\s*(.*)/', trim($rank), $matches);
166
-				if ($matched) {
167
-					$unpipedArray[$matches[1]] = $matches[2];
168
-				}
169
-			endforeach;
170
-			return $unpipedArray;
171
-		}
154
+        /**
155
+         * Splits String 'a=b|c=d|e=f' into an array('a'=>'b', 'c'=>'d', 'e'=>'f')
156
+         *
157
+         * @param string $pipeString
158
+         * @return array
159
+         */
160
+        protected function _pipeSplitter($pipeString) {
161
+            $unpipedArray = array();
162
+            $ranks = explode('|', $pipeString);
163
+            foreach ($ranks as $rank) :
164
+                $matches = array();
165
+                $matched = preg_match('/(\w+)\s*=\s*(.*)/', trim($rank), $matches);
166
+                if ($matched) {
167
+                    $unpipedArray[$matches[1]] = $matches[2];
168
+                }
169
+            endforeach;
170
+            return $unpipedArray;
171
+        }
172 172
 
173
-		protected static function _getIp() {
174
-			$ip = null;
175
-			if (Configure::read('Saito.Settings.store_ip')):
176
-				$ip = env('REMOTE_ADDR');
177
-				if (Configure::read('Saito.Settings.store_ip_anonymized')):
178
-					$ip = self::_anonymizeIp($ip);
179
-				endif;
180
-			endif;
181
-			return $ip;
182
-		}
173
+        protected static function _getIp() {
174
+            $ip = null;
175
+            if (Configure::read('Saito.Settings.store_ip')):
176
+                $ip = env('REMOTE_ADDR');
177
+                if (Configure::read('Saito.Settings.store_ip_anonymized')):
178
+                    $ip = self::_anonymizeIp($ip);
179
+                endif;
180
+            endif;
181
+            return $ip;
182
+        }
183 183
 
184
-		/**
185
-		 * Dispatches an event
186
-		 *
187
-		 * - Always passes the issuing model class as subject
188
-		 * - Wrapper for CakeEvent boilerplate code
189
-		 * - Easier to test
190
-		 *
191
-		 * @param string $event event identifier `Model.<modelname>.<event>`
192
-		 * @param array $data additional event data
193
-		 */
194
-		protected function _dispatchEvent($event, $data = []) {
195
-			$this->getEventManager()->dispatch(new CakeEvent($event, $this, $data));
196
-			// propagate event on Saito's event bus
197
-			$this->dispatchSaitoEvent($event, $data);
198
-		}
184
+        /**
185
+         * Dispatches an event
186
+         *
187
+         * - Always passes the issuing model class as subject
188
+         * - Wrapper for CakeEvent boilerplate code
189
+         * - Easier to test
190
+         *
191
+         * @param string $event event identifier `Model.<modelname>.<event>`
192
+         * @param array $data additional event data
193
+         */
194
+        protected function _dispatchEvent($event, $data = []) {
195
+            $this->getEventManager()->dispatch(new CakeEvent($event, $this, $data));
196
+            // propagate event on Saito's event bus
197
+            $this->dispatchSaitoEvent($event, $data);
198
+        }
199 199
 
200
-		public function dispatchSaitoEvent($event, $data) {
201
-			if (!$this->_SEM) {
202
-				$this->_SEM = SaitoEventManager::getInstance();
203
-			}
204
-			$this->_SEM->dispatch($event, $data + ['Model' => $this]);
205
-		}
200
+        public function dispatchSaitoEvent($event, $data) {
201
+            if (!$this->_SEM) {
202
+                $this->_SEM = SaitoEventManager::getInstance();
203
+            }
204
+            $this->_SEM->dispatch($event, $data + ['Model' => $this]);
205
+        }
206 206
 
207
-		/**
208
-		 * Rough and tough ip anonymizer
209
-		 *
210
-		 * @param string $ip
211
-		 * @return string
212
-		 */
213
-		protected static function _anonymizeIp($ip) {
214
-			$strlen = strlen($ip);
215
-			if ($strlen > 6) :
216
-				$divider = (int)floor($strlen / 4) + 1;
217
-				$ip = substr_replace($ip, '…', $divider, $strlen - (2 * $divider));
218
-			endif;
207
+        /**
208
+         * Rough and tough ip anonymizer
209
+         *
210
+         * @param string $ip
211
+         * @return string
212
+         */
213
+        protected static function _anonymizeIp($ip) {
214
+            $strlen = strlen($ip);
215
+            if ($strlen > 6) :
216
+                $divider = (int)floor($strlen / 4) + 1;
217
+                $ip = substr_replace($ip, '…', $divider, $strlen - (2 * $divider));
218
+            endif;
219 219
 
220
-			return $ip;
221
-		}
220
+            return $ip;
221
+        }
222 222
 
223
-		/**
224
-		 * gets app setting
225
-		 *
226
-		 * falls back to local definition if available
227
-		 *
228
-		 * @param $name
229
-		 * @return mixed
230
-		 * @throws UnexpectedValueException
231
-		 */
232
-		protected function _setting($name) {
233
-			$setting = Configure::read('Saito.Settings.' . $name);
234
-			if ($setting !== null) {
235
-				return $setting;
236
-			}
237
-			if (isset($this->_settings[$name])) {
238
-				return $this->_settings[$name];
239
-			}
240
-			throw new UnexpectedValueException;
241
-		}
223
+        /**
224
+         * gets app setting
225
+         *
226
+         * falls back to local definition if available
227
+         *
228
+         * @param $name
229
+         * @return mixed
230
+         * @throws UnexpectedValueException
231
+         */
232
+        protected function _setting($name) {
233
+            $setting = Configure::read('Saito.Settings.' . $name);
234
+            if ($setting !== null) {
235
+                return $setting;
236
+            }
237
+            if (isset($this->_settings[$name])) {
238
+                return $this->_settings[$name];
239
+            }
240
+            throw new UnexpectedValueException;
241
+        }
242 242
 
243
-		public function isUniqueCiString($fields) {
244
-			// lazy: only one field
245
-			if (!is_array($fields) || count($fields) > 1) {
246
-				throw InvalidArgumentException();
247
-			}
248
-			$key = key($fields);
249
-			$fields = [
250
-				"LOWER({$this->alias}.{$key})" => mb_strtolower(current($fields))
251
-			];
252
-			return $this->isUnique($fields);
253
-		}
243
+        public function isUniqueCiString($fields) {
244
+            // lazy: only one field
245
+            if (!is_array($fields) || count($fields) > 1) {
246
+                throw InvalidArgumentException();
247
+            }
248
+            $key = key($fields);
249
+            $fields = [
250
+                "LOWER({$this->alias}.{$key})" => mb_strtolower(current($fields))
251
+            ];
252
+            return $this->isUnique($fields);
253
+        }
254 254
 
255
-		/**
256
-		 * Inclusive Validation::range()
257
-		 *
258
-		 * @param array $check
259
-		 * @param float $lower
260
-		 * @param float $upper
261
-		 * @return bool
262
-		 * @see https://github.com/cakephp/cakephp/issues/3304
263
-		 */
264
-		public function inRange($check, $lower = null, $upper = null) {
265
-			$check = reset($check);
266
-			if (!is_numeric($check)) {
267
-				return false;
268
-			}
269
-			if (isset($lower) && isset($upper)) {
270
-				return ($check >= $lower && $check <= $upper);
271
-			}
272
-			// fallback to 'parent'
273
-			return Validation::range($check, $lower, $upper);
274
-		}
255
+        /**
256
+         * Inclusive Validation::range()
257
+         *
258
+         * @param array $check
259
+         * @param float $lower
260
+         * @param float $upper
261
+         * @return bool
262
+         * @see https://github.com/cakephp/cakephp/issues/3304
263
+         */
264
+        public function inRange($check, $lower = null, $upper = null) {
265
+            $check = reset($check);
266
+            if (!is_numeric($check)) {
267
+                return false;
268
+            }
269
+            if (isset($lower) && isset($upper)) {
270
+                return ($check >= $lower && $check <= $upper);
271
+            }
272
+            // fallback to 'parent'
273
+            return Validation::range($check, $lower, $upper);
274
+        }
275 275
 
276
-		/**
277
-		 * Logs current SQL log
278
-		 *
279
-		 * Set debug to 2 to enable SQL logging!
280
-		 */
281
-		public function logSql() {
282
-			if (Configure::read('debug') < 2) {
283
-				trigger_error('You must set debug level to at least 2 to enable SQL-logging',
284
-					E_USER_NOTICE);
285
-			}
286
-			$dbo = $this->getDatasource();
287
-			$logs = $dbo->getLog();
288
-			$this->log($logs['log']);
289
-		}
276
+        /**
277
+         * Logs current SQL log
278
+         *
279
+         * Set debug to 2 to enable SQL logging!
280
+         */
281
+        public function logSql() {
282
+            if (Configure::read('debug') < 2) {
283
+                trigger_error('You must set debug level to at least 2 to enable SQL-logging',
284
+                    E_USER_NOTICE);
285
+            }
286
+            $dbo = $this->getDatasource();
287
+            $logs = $dbo->getLog();
288
+            $this->log($logs['log']);
289
+        }
290 290
 
291
-	}
291
+    }
Please login to merge, or discard this patch.
app/Model/UserOnline.php 1 patch
Indentation   +96 added lines, -96 removed lines patch added patch discarded remove patch
@@ -3,35 +3,35 @@  discard block
 block discarded – undo
3 3
 /**
4 4
  *  Class UserOnline
5 5
  */
6
-	class UserOnline extends AppModel {
6
+    class UserOnline extends AppModel {
7 7
 
8
-		public $name = 'UserOnline';
8
+        public $name = 'UserOnline';
9 9
 
10
-		public $useTable = 'useronline';
10
+        public $useTable = 'useronline';
11 11
 
12
-		public $actsAs = ['Containable'];
12
+        public $actsAs = ['Containable'];
13 13
 
14
-		public $belongsTo = [
15
-			'User' => [
16
-				'className' => 'User',
17
-				'foreignKey' => 'user_id'
18
-			]
19
-		];
14
+        public $belongsTo = [
15
+            'User' => [
16
+                'className' => 'User',
17
+                'foreignKey' => 'user_id'
18
+            ]
19
+        ];
20 20
 
21
-		public $validate = [
22
-			'uuid' => [
23
-				'rule' => 'isUnique',
24
-				'required' => true,
25
-				'allowEmpty' => false
26
-			]
27
-		];
21
+        public $validate = [
22
+            'uuid' => [
23
+                'rule' => 'isUnique',
24
+                'required' => true,
25
+                'allowEmpty' => false
26
+            ]
27
+        ];
28 28
 
29 29
 /**
30 30
  * Time in seconds until a user is considered offline
31 31
  *
32 32
  * @var int
33 33
  */
34
-		public $timeUntilOffline = 1200;
34
+        public $timeUntilOffline = 1200;
35 35
 
36 36
 /**
37 37
  * Sets user with `$id` online
@@ -40,72 +40,72 @@  discard block
 block discarded – undo
40 40
  * @param boolean $loggedIn user is logged-in
41 41
  * @throws InvalidArgumentException
42 42
  */
43
-		public function setOnline($id, $loggedIn) {
44
-			if (empty($id)) {
45
-				throw new InvalidArgumentException('Invalid Argument $id in setOnline()');
46
-			}
47
-			if (!is_bool($loggedIn)) {
48
-				throw new InvalidArgumentException('Invalid Argument $logged_in in setOnline()');
49
-			}
50
-			$now = time();
51
-
52
-			$id = $this->_getShortendedId($id);
53
-			$data = [
54
-				'UserOnline' => [
55
-					'uuid' => $id,
56
-					'logged_in' => $loggedIn,
57
-					'time' => $now
58
-				]
59
-			];
60
-
61
-			if ($loggedIn) {
62
-				$data['UserOnline']['user_id'] = $id;
63
-			}
64
-
65
-			$user = $this->find('first', ['conditions' => ['uuid' => $id],
66
-				'recursive' => -1, 'callbacks' => false]);
67
-
68
-			if ($user) {
69
-				// only hit database if timestamp is outdated
70
-				if ($user['UserOnline']['time'] < ($now - $this->timeUntilOffline)) {
71
-					$this->id = $user['UserOnline']['id'];
72
-					$this->save($data);
73
-				}
74
-			} else {
75
-				$this->id = null;
76
-				$this->create();
77
-				$this->save($data);
78
-			}
79
-
80
-			$this->_deleteOutdated();
81
-		}
82
-
83
-		/**
84
-		 * Removes user with uuid `$id` from UserOnline
85
-		 *
86
-		 * @param $id
87
-		 *
88
-		 * @return bool
89
-		 */
90
-		public function setOffline($id) {
91
-			$id = $this->_getShortendedId($id);
92
-			return $this->deleteAll(['UserOnline.uuid' => $id], false);
93
-		}
94
-
95
-		public function getLoggedIn() {
96
-			Stopwatch::start('UserOnline->getLoggedIn()');
97
-			$loggedInUsers = $this->find(
98
-				'all',
99
-				[
100
-					'contain' => 'User',
101
-					'conditions' => ['UserOnline.logged_in' => true],
102
-					'fields' => ['User.id', 'User.username', 'User.user_type'],
103
-					'order' => ['LOWER(User.username)' => 'ASC']
104
-				]
105
-			);
106
-			Stopwatch::stop('UserOnline->getLoggedIn()');
107
-			return $loggedInUsers;
108
-		}
43
+        public function setOnline($id, $loggedIn) {
44
+            if (empty($id)) {
45
+                throw new InvalidArgumentException('Invalid Argument $id in setOnline()');
46
+            }
47
+            if (!is_bool($loggedIn)) {
48
+                throw new InvalidArgumentException('Invalid Argument $logged_in in setOnline()');
49
+            }
50
+            $now = time();
51
+
52
+            $id = $this->_getShortendedId($id);
53
+            $data = [
54
+                'UserOnline' => [
55
+                    'uuid' => $id,
56
+                    'logged_in' => $loggedIn,
57
+                    'time' => $now
58
+                ]
59
+            ];
60
+
61
+            if ($loggedIn) {
62
+                $data['UserOnline']['user_id'] = $id;
63
+            }
64
+
65
+            $user = $this->find('first', ['conditions' => ['uuid' => $id],
66
+                'recursive' => -1, 'callbacks' => false]);
67
+
68
+            if ($user) {
69
+                // only hit database if timestamp is outdated
70
+                if ($user['UserOnline']['time'] < ($now - $this->timeUntilOffline)) {
71
+                    $this->id = $user['UserOnline']['id'];
72
+                    $this->save($data);
73
+                }
74
+            } else {
75
+                $this->id = null;
76
+                $this->create();
77
+                $this->save($data);
78
+            }
79
+
80
+            $this->_deleteOutdated();
81
+        }
82
+
83
+        /**
84
+         * Removes user with uuid `$id` from UserOnline
85
+         *
86
+         * @param $id
87
+         *
88
+         * @return bool
89
+         */
90
+        public function setOffline($id) {
91
+            $id = $this->_getShortendedId($id);
92
+            return $this->deleteAll(['UserOnline.uuid' => $id], false);
93
+        }
94
+
95
+        public function getLoggedIn() {
96
+            Stopwatch::start('UserOnline->getLoggedIn()');
97
+            $loggedInUsers = $this->find(
98
+                'all',
99
+                [
100
+                    'contain' => 'User',
101
+                    'conditions' => ['UserOnline.logged_in' => true],
102
+                    'fields' => ['User.id', 'User.username', 'User.user_type'],
103
+                    'order' => ['LOWER(User.username)' => 'ASC']
104
+                ]
105
+            );
106
+            Stopwatch::stop('UserOnline->getLoggedIn()');
107
+            return $loggedInUsers;
108
+        }
109 109
 
110 110
 /**
111 111
  * deletes gone user
@@ -114,15 +114,15 @@  discard block
 block discarded – undo
114 114
  *
115 115
  * @param string $timeDiff in minutes
116 116
  */
117
-		protected function _deleteOutdated($timeDiff = null) {
118
-			if ($timeDiff === null) {
119
-				$timeDiff = $this->timeUntilOffline;
120
-			}
121
-			$this->deleteAll(['time <' => time() - ($timeDiff)], false);
122
-		}
123
-
124
-		protected function _getShortendedId($id) {
125
-			return substr($id, 0, 32);
126
-		}
127
-
128
-	}
129 117
\ No newline at end of file
118
+        protected function _deleteOutdated($timeDiff = null) {
119
+            if ($timeDiff === null) {
120
+                $timeDiff = $this->timeUntilOffline;
121
+            }
122
+            $this->deleteAll(['time <' => time() - ($timeDiff)], false);
123
+        }
124
+
125
+        protected function _getShortendedId($id) {
126
+            return substr($id, 0, 32);
127
+        }
128
+
129
+    }
130 130
\ No newline at end of file
Please login to merge, or discard this patch.
app/Model/Smiley.php 1 patch
Indentation   +64 added lines, -64 removed lines patch added patch discarded remove patch
@@ -1,79 +1,79 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-	App::uses('AppSettingModel', 'Lib/Model');
3
+    App::uses('AppSettingModel', 'Lib/Model');
4 4
 
5
-	class Smiley extends AppSettingModel {
5
+    class Smiley extends AppSettingModel {
6 6
 
7
-		public $name = 'Smiley';
7
+        public $name = 'Smiley';
8 8
 
9
-		public $validate = [
10
-			'sort' => [
11
-				'numeric' => [
12
-					'rule' => ['numeric']
13
-				]
14
-			]
15
-		];
9
+        public $validate = [
10
+            'sort' => [
11
+                'numeric' => [
12
+                    'rule' => ['numeric']
13
+                ]
14
+            ]
15
+        ];
16 16
 
17
-		public $hasMany = [
18
-			'SmileyCode' => [
19
-				'className' => 'SmileyCode',
20
-				'foreignKey' => 'smiley_id'
21
-			]
22
-		];
17
+        public $hasMany = [
18
+            'SmileyCode' => [
19
+                'className' => 'SmileyCode',
20
+                'foreignKey' => 'smiley_id'
21
+            ]
22
+        ];
23 23
 
24
-		protected $_smilies;
24
+        protected $_smilies;
25 25
 
26
-		public function load($force = false) {
27
-			if ($force) {
28
-				$this->_smilies = null;
29
-				$this->clearCache();
30
-			}
26
+        public function load($force = false) {
27
+            if ($force) {
28
+                $this->_smilies = null;
29
+                $this->clearCache();
30
+            }
31 31
 
32
-			if ($this->_smilies !== null) {
33
-				return $this->_smilies;
34
-			}
32
+            if ($this->_smilies !== null) {
33
+                return $this->_smilies;
34
+            }
35 35
 
36
-			$this->_smilies = [];
37
-			$smiliesRaw = $this->find('all', ['order' => 'Smiley.sort ASC']);
36
+            $this->_smilies = [];
37
+            $smiliesRaw = $this->find('all', ['order' => 'Smiley.sort ASC']);
38 38
 
39
-			foreach ($smiliesRaw as $smileyRaw) {
40
-				// 'image' defaults to 'icon'
41
-				if (empty($smileyRaw['Smiley']['image'])) {
42
-					$smileyRaw['Smiley']['image'] = $smileyRaw['Smiley']['icon'];
43
-				}
44
-				// @bogus: if title is unknown it should be a problem
45
-				if ($smileyRaw['Smiley']['title'] === null) {
46
-					$smileyRaw['Smiley']['title'] = '';
47
-				}
48
-				// set type
49
-				$smileyRaw['Smiley']['type'] = $this->_getType($smileyRaw['Smiley']);
39
+            foreach ($smiliesRaw as $smileyRaw) {
40
+                // 'image' defaults to 'icon'
41
+                if (empty($smileyRaw['Smiley']['image'])) {
42
+                    $smileyRaw['Smiley']['image'] = $smileyRaw['Smiley']['icon'];
43
+                }
44
+                // @bogus: if title is unknown it should be a problem
45
+                if ($smileyRaw['Smiley']['title'] === null) {
46
+                    $smileyRaw['Smiley']['title'] = '';
47
+                }
48
+                // set type
49
+                $smileyRaw['Smiley']['type'] = $this->_getType($smileyRaw['Smiley']);
50 50
 
51
-				//= adds smiley-data to every smiley-code
52
-				if (isset($smileyRaw['SmileyCode'])) {
53
-					foreach ($smileyRaw['SmileyCode'] as $smileyRawCode) {
54
-						unset($smileyRaw['Smiley']['id']);
55
-						$smileyRaw['Smiley']['code'] = $smileyRawCode['code'];
56
-						$this->_smilies[] = $smileyRaw['Smiley'];
57
-					}
58
-				}
59
-			}
51
+                //= adds smiley-data to every smiley-code
52
+                if (isset($smileyRaw['SmileyCode'])) {
53
+                    foreach ($smileyRaw['SmileyCode'] as $smileyRawCode) {
54
+                        unset($smileyRaw['Smiley']['id']);
55
+                        $smileyRaw['Smiley']['code'] = $smileyRawCode['code'];
56
+                        $this->_smilies[] = $smileyRaw['Smiley'];
57
+                    }
58
+                }
59
+            }
60 60
 
61
-			Stopwatch::stop('Smiley::load');
62
-			return $this->_smilies;
63
-		}
61
+            Stopwatch::stop('Smiley::load');
62
+            return $this->_smilies;
63
+        }
64 64
 
65
-		/**
66
-		 * detects smiley type
67
-		 *
68
-		 * @param array $smiley
69
-		 * @return string image|font
70
-		 */
71
-		protected function _getType($smiley) {
72
-			if (preg_match('/^.*\.[\w]{3,4}$/i', $smiley['image'])) {
73
-				return 'image';
74
-			} else {
75
-				return 'font';
76
-			}
77
-		}
65
+        /**
66
+         * detects smiley type
67
+         *
68
+         * @param array $smiley
69
+         * @return string image|font
70
+         */
71
+        protected function _getType($smiley) {
72
+            if (preg_match('/^.*\.[\w]{3,4}$/i', $smiley['image'])) {
73
+                return 'image';
74
+            } else {
75
+                return 'font';
76
+            }
77
+        }
78 78
 
79
-	}
79
+    }
Please login to merge, or discard this patch.
app/Model/UserBlock.php 1 patch
Indentation   +131 added lines, -131 removed lines patch added patch discarded remove patch
@@ -1,147 +1,147 @@
 block discarded – undo
1 1
 <?php
2 2
 
3
-	App::uses('AppModel', 'Model');
4
-	App::import('Lib', 'UserBlocker');
3
+    App::uses('AppModel', 'Model');
4
+    App::import('Lib', 'UserBlocker');
5 5
 
6
-	/**
7
-	 * UserBlock Model
8
-	 *
9
-	 * states
10
-	 */
11
-	class UserBlock extends AppModel {
6
+    /**
7
+     * UserBlock Model
8
+     *
9
+     * states
10
+     */
11
+    class UserBlock extends AppModel {
12 12
 
13
-		public $actsAs = [
14
-			'Containable'
15
-		];
13
+        public $actsAs = [
14
+            'Containable'
15
+        ];
16 16
 
17
-		public $belongsTo = [
18
-			'User' => [
19
-				'className' => 'User',
20
-				'fields' => ['id', 'username'],
21
-				'foreignKey' => 'user_id'
22
-			],
23
-			'By' => [
24
-				'className' => 'User',
25
-				'fields' => ['id', 'username'],
26
-				'foreignKey' => 'blocked_by_user_id'
27
-			]
28
-		];
17
+        public $belongsTo = [
18
+            'User' => [
19
+                'className' => 'User',
20
+                'fields' => ['id', 'username'],
21
+                'foreignKey' => 'user_id'
22
+            ],
23
+            'By' => [
24
+                'className' => 'User',
25
+                'fields' => ['id', 'username'],
26
+                'foreignKey' => 'blocked_by_user_id'
27
+            ]
28
+        ];
29 29
 
30
-		public $findMethods = [
31
-			'toGc' => true
32
-		];
30
+        public $findMethods = [
31
+            'toGc' => true
32
+        ];
33 33
 
34
-		public $validate = [
35
-			'ends' => [
36
-				'rule' => ['datetime'],
37
-				'allowEmpty' => true
38
-			]
39
-		];
34
+        public $validate = [
35
+            'ends' => [
36
+                'rule' => ['datetime'],
37
+                'allowEmpty' => true
38
+            ]
39
+        ];
40 40
 
41
-		public function block($Blocker, $userId, $options) {
42
-			$Blocker->setUserBlockModel($this);
43
-			$success = $Blocker->block($userId, $options);
44
-			if ($success) {
45
-				$this->_updateIsBlocked($userId);
46
-			}
47
-			return $success;
48
-		}
41
+        public function block($Blocker, $userId, $options) {
42
+            $Blocker->setUserBlockModel($this);
43
+            $success = $Blocker->block($userId, $options);
44
+            if ($success) {
45
+                $this->_updateIsBlocked($userId);
46
+            }
47
+            return $success;
48
+        }
49 49
 
50
-		public function getBlockEndsForUser($userId) {
51
-			$block = $this->find('first', [
52
-				'contain' => false,
53
-				'conditions' => ['user_id' => $userId, 'ended' => null],
54
-				'order' => ['ends' => 'asc']
55
-			]);
56
-			return $block['UserBlock']['ends'];
57
-		}
50
+        public function getBlockEndsForUser($userId) {
51
+            $block = $this->find('first', [
52
+                'contain' => false,
53
+                'conditions' => ['user_id' => $userId, 'ended' => null],
54
+                'order' => ['ends' => 'asc']
55
+            ]);
56
+            return $block['UserBlock']['ends'];
57
+        }
58 58
 
59
-		/**
60
-		 * @param $id
61
-		 * @return bool true if unblocking was successful, false otherwise
62
-		 * @throws RuntimeException
63
-		 * @throws InvalidArgumentException
64
-		 */
65
-		public function unblock($id) {
66
-			$block = $this->find('first', [
67
-				'contain' => false,
68
-				'conditions' => ['id' => $id, 'ended' => null]
69
-			]);
70
-			if (empty($block)) {
71
-				throw new InvalidArgumentException(
72
-					"No active block with id $id found.",
73
-					1420485052
74
-				);
75
-			}
76
-			$success = (bool)$this->save([
77
-				'id' => $id,
78
-				'ended' => bDate(),
79
-				'ends' => null
80
-			]);
81
-			if (!$success) {
82
-				throw new RuntimeException;
83
-			}
84
-			$this->_updateIsBlocked($block[$this->alias]['user_id']);
85
-			return $success;
86
-		}
59
+        /**
60
+         * @param $id
61
+         * @return bool true if unblocking was successful, false otherwise
62
+         * @throws RuntimeException
63
+         * @throws InvalidArgumentException
64
+         */
65
+        public function unblock($id) {
66
+            $block = $this->find('first', [
67
+                'contain' => false,
68
+                'conditions' => ['id' => $id, 'ended' => null]
69
+            ]);
70
+            if (empty($block)) {
71
+                throw new InvalidArgumentException(
72
+                    "No active block with id $id found.",
73
+                    1420485052
74
+                );
75
+            }
76
+            $success = (bool)$this->save([
77
+                'id' => $id,
78
+                'ended' => bDate(),
79
+                'ends' => null
80
+            ]);
81
+            if (!$success) {
82
+                throw new RuntimeException;
83
+            }
84
+            $this->_updateIsBlocked($block[$this->alias]['user_id']);
85
+            return $success;
86
+        }
87 87
 
88
-		/**
89
-		 * Garbage collection
90
-		 *
91
-		 * called hourly from User model
92
-		 */
93
-		public function gc() {
94
-			$expired = $this->find('toGc');
95
-			foreach ($expired as $block) {
96
-				$this->unblock($block[$this->alias]['id']);
97
-			}
98
-		}
88
+        /**
89
+         * Garbage collection
90
+         *
91
+         * called hourly from User model
92
+         */
93
+        public function gc() {
94
+            $expired = $this->find('toGc');
95
+            foreach ($expired as $block) {
96
+                $this->unblock($block[$this->alias]['id']);
97
+            }
98
+        }
99 99
 
100
-		public function getAll() {
101
-			$blocklist = $this->find('all', [
102
-				'contain' => ['By', 'User'],
103
-				'order' => ['UserBlock.id' => 'DESC']
104
-			]);
105
-			$o = [];
106
-			foreach ($blocklist as $k => $b) {
107
-				$o[$k] = $b['UserBlock'];
108
-				$o[$k]['By'] = $b['By'];
109
-				$o[$k]['User'] = $b['User'];
110
-			}
111
-			return $o;
112
-		}
100
+        public function getAll() {
101
+            $blocklist = $this->find('all', [
102
+                'contain' => ['By', 'User'],
103
+                'order' => ['UserBlock.id' => 'DESC']
104
+            ]);
105
+            $o = [];
106
+            foreach ($blocklist as $k => $b) {
107
+                $o[$k] = $b['UserBlock'];
108
+                $o[$k]['By'] = $b['By'];
109
+                $o[$k]['User'] = $b['User'];
110
+            }
111
+            return $o;
112
+        }
113 113
 
114
-		public function getAllActive() {
115
-			$blocklist = $this->find('all', [
116
-				'contain' => false,
117
-				'conditions' => ['ended' => null],
118
-				'order' => ['UserBlock.id' => 'DESC']
119
-			]);
120
-			return $blocklist;
121
-		}
114
+        public function getAllActive() {
115
+            $blocklist = $this->find('all', [
116
+                'contain' => false,
117
+                'conditions' => ['ended' => null],
118
+                'order' => ['UserBlock.id' => 'DESC']
119
+            ]);
120
+            return $blocklist;
121
+        }
122 122
 
123
-		protected function _findToGc($state, $query, $results = array()) {
124
-			if ($state === 'before') {
125
-				$query['contain'] = false;
126
-				$query['conditions'] = [
127
-					'ends !=' => null,
128
-					'ends <' => bDate(),
129
-					'ended' => null
130
-				];
131
-				return $query;
132
-			}
133
-			return $results;
134
-		}
123
+        protected function _findToGc($state, $query, $results = array()) {
124
+            if ($state === 'before') {
125
+                $query['contain'] = false;
126
+                $query['conditions'] = [
127
+                    'ends !=' => null,
128
+                    'ends <' => bDate(),
129
+                    'ended' => null
130
+                ];
131
+                return $query;
132
+            }
133
+            return $results;
134
+        }
135 135
 
136
-		protected function _updateIsBlocked($userId) {
137
-			$blocks = $this->find('first', [
138
-				'contain' => false,
139
-				'conditions' => [
140
-					'ended' => null,
141
-					'user_id' => $userId
142
-				]
143
-			]);
144
-			$this->User->save(['id' => $userId, 'user_lock' => !empty($blocks)]);
145
-		}
136
+        protected function _updateIsBlocked($userId) {
137
+            $blocks = $this->find('first', [
138
+                'contain' => false,
139
+                'conditions' => [
140
+                    'ended' => null,
141
+                    'user_id' => $userId
142
+                ]
143
+            ]);
144
+            $this->User->save(['id' => $userId, 'user_lock' => !empty($blocks)]);
145
+        }
146 146
 
147
-	}
147
+    }
Please login to merge, or discard this patch.