Passed
Branch develop (963cc8)
by Schlaefer
09:31
created

EntriesController::view()   A

Complexity

Conditions 5
Paths 5

Size

Total Lines 44
Code Lines 22

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 5
eloc 22
nc 5
nop 1
dl 0
loc 44
rs 9.2568
c 1
b 0
f 0
1
<?php
2
3
declare(strict_types=1);
4
5
/**
6
 * Saito - The Threaded Web Forum
7
 *
8
 * @copyright Copyright (c) the Saito Project Developers
9
 * @link https://github.com/Schlaefer/Saito
10
 * @license http://opensource.org/licenses/MIT
11
 */
12
13
namespace App\Controller;
14
15
use App\Controller\Component\AutoReloadComponent;
16
use App\Controller\Component\MarkAsReadComponent;
17
use App\Controller\Component\RefererComponent;
18
use App\Controller\Component\ThreadsComponent;
19
use App\Model\Table\EntriesTable;
20
use Cake\Core\Configure;
21
use Cake\Event\Event;
22
use Cake\Http\Exception\BadRequestException;
23
use Cake\Http\Exception\MethodNotAllowedException;
24
use Cake\Http\Exception\NotFoundException;
25
use Cake\Http\Response;
26
use Cake\Routing\RequestActionTrait;
27
use Saito\Exception\SaitoForbiddenException;
28
use Saito\Posting\Posting;
29
use Saito\Posting\PostingInterface;
30
use Saito\User\CurrentUser\CurrentUserInterface;
31
use Stopwatch\Lib\Stopwatch;
32
33
/**
34
 * Class EntriesController
35
 *
36
 * @property CurrentUserInterface $CurrentUser
37
 * @property EntriesTable $Entries
38
 * @property MarkAsReadComponent $MarkAsRead
39
 * @property RefererComponent $Referer
40
 * @property ThreadsComponent $Threads
41
 */
42
class EntriesController extends AppController
43
{
44
    use RequestActionTrait;
0 ignored issues
show
Deprecated Code introduced by
The trait Cake\Routing\RequestActionTrait has been deprecated: 3.3.0 Use view cells instead. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-deprecated  annotation

44
    use /** @scrutinizer ignore-deprecated */ RequestActionTrait;

This trait has been deprecated. The supplier of the trait has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the trait will be removed and what other trait to use instead.

Loading history...
45
46
    public $helpers = ['Posting', 'Text'];
47
48
    public $actionAuthConfig = [
49
        'ajaxToggle' => 'mod',
50
        'merge' => 'mod',
51
        'delete' => 'mod'
52
    ];
53
54
    /**
55
     * {@inheritDoc}
56
     */
57
    public function initialize()
58
    {
59
        parent::initialize();
60
61
        $this->loadComponent('MarkAsRead');
62
        $this->loadComponent('Referer');
63
        $this->loadComponent('Threads');
64
    }
65
66
    /**
67
     * posting index
68
     *
69
     * @return void|\Cake\Network\Response
70
     */
71
    public function index()
72
    {
73
        Stopwatch::start('Entries->index()');
74
75
        //= determine user sort order
76
        $sortKey = 'last_answer';
77
        if (!$this->CurrentUser->get('user_sort_last_answer')) {
78
            $sortKey = 'time';
79
        }
80
        $order = ['fixed' => 'DESC', $sortKey => 'DESC'];
81
82
        //= get threads
83
        $threads = $this->Threads->paginate($order);
84
        $this->set('entries', $threads);
85
86
        $currentPage = (int)$this->request->getQuery('page') ?: 1;
87
        if ($currentPage > 1) {
88
            $this->set('titleForLayout', __('page') . ' ' . $currentPage);
89
        }
90
        if ($currentPage === 1) {
91
            if ($this->MarkAsRead->refresh()) {
92
                return $this->redirect(['action' => 'index']);
93
            }
94
            $this->MarkAsRead->next();
95
        }
96
97
        // @bogus
98
        $this->request->getSession()->write('paginator.lastPage', $currentPage);
99
        $this->set('showDisclaimer', true);
100
        $this->set('showBottomNavigation', true);
101
        $this->set('allowThreadCollapse', true);
102
        $this->Slidetabs->show();
103
104
        $this->_setupCategoryChooser($this->CurrentUser);
105
106
        /** @var AutoReloadComponent */
107
        $autoReload = $this->loadComponent('AutoReload');
108
        $autoReload->after($this->CurrentUser);
0 ignored issues
show
Bug introduced by
The method after() does not exist on Cake\Controller\Component. It seems like you code against a sub-type of Cake\Controller\Component such as Cake\Controller\Component\FlashComponent or App\Controller\Component\AutoReloadComponent or Cake\Controller\Component\PaginatorComponent. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

108
        $autoReload->/** @scrutinizer ignore-call */ 
109
                     after($this->CurrentUser);
Loading history...
109
110
        Stopwatch::stop('Entries->index()');
111
    }
112
113
    /**
114
     * Mix view
115
     *
116
     * @param string $tid thread-ID
117
     * @return void|Response
118
     * @throws NotFoundException
119
     */
120
    public function mix($tid)
121
    {
122
        $tid = (int)$tid;
123
        if ($tid <= 0) {
124
            throw new BadRequestException();
125
        }
126
127
        $postings = $this->Entries->treeForNode(
0 ignored issues
show
Bug introduced by
Are you sure the assignment to $postings is correct as $this->Entries->treeForN...e, 'complete' => true)) targeting App\Model\Table\EntriesTable::treeForNode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is assigned to a variable.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
$object = $a->getObject();

The method getObject() can return nothing but null, so it makes no sense to assign that value to a variable.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
128
            $tid,
129
            ['root' => true, 'complete' => true]
130
        );
131
132
        /// redirect sub-posting to mix view of thread
133
        if (!$postings) {
0 ignored issues
show
introduced by
$postings is of type null, thus it always evaluated to false.
Loading history...
134
            $post = $this->Entries->find()
135
                ->select(['tid'])
136
                ->where(['id' => $tid])
137
                ->first();
138
            if (!empty($post)) {
139
                return $this->redirect([$post->get('tid'), '#' => $tid], 301);
140
            }
141
            throw new NotFoundException;
142
        }
143
144
        // check if anonymous tries to access internal categories
145
        $root = $postings;
146
        if (!$this->CurrentUser->getCategories()->permission('read', $root->get('category'))) {
147
            return $this->_requireAuth();
148
        }
149
150
        $this->_setRootEntry($root);
151
        $this->Title->setFromPosting($root, __('view.type.mix'));
152
153
        $this->set('showBottomNavigation', true);
154
        $this->set('entries', $postings);
155
156
        $this->_showAnsweringPanel();
157
158
        $this->Threads->incrementViews($root, 'thread');
159
        $this->MarkAsRead->thread($postings);
160
    }
161
162
    /**
163
     * load front page force all entries mark-as-read
164
     *
165
     * @return void
166
     */
167
    public function update()
168
    {
169
        $this->autoRender = false;
170
        $this->CurrentUser->getLastRefresh()->set();
171
        $this->redirect('/entries/index');
172
    }
173
174
    /**
175
     * Outputs raw markup of an posting $id
176
     *
177
     * @param string $id posting-ID
178
     * @return void
179
     */
180
    public function source($id = null)
181
    {
182
        $this->viewBuilder()->enableAutoLayout(false);
183
        $this->view($id);
184
    }
185
186
    /**
187
     * View posting.
188
     *
189
     * @param string $id posting-ID
190
     * @return \Cake\Network\Response|void
191
     */
192
    public function view($id = null)
193
    {
194
        Stopwatch::start('Entries->view()');
195
196
        // redirect if no id is given
197
        if (!$id) {
198
            $this->Flash->set(__('Invalid post'), ['element' => 'error']);
199
200
            return $this->redirect(['action' => 'index']);
201
        }
202
203
        $entry = $this->Entries->get($id);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $primaryKey of App\Model\Table\EntriesTable::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

203
        $entry = $this->Entries->get(/** @scrutinizer ignore-type */ $id);
Loading history...
204
205
        // redirect if posting doesn't exists
206
        if ($entry == false) {
207
            $this->Flash->set(__('Invalid post'));
208
209
            return $this->redirect('/');
210
        }
211
212
        if (!$this->CurrentUser->getCategories()->permission('read', $entry->get('category'))) {
213
            return $this->_requireAuth();
214
        }
215
216
        $this->set('entry', $entry);
217
        $this->Threads->incrementViews($entry);
218
        $this->_setRootEntry($entry);
219
        $this->_showAnsweringPanel();
220
221
        $this->MarkAsRead->posting($entry);
222
223
        // inline open
224
        if ($this->request->is('ajax')) {
225
            return $this->render('/Element/entry/view_posting');
226
        }
227
228
        // full page request
229
        $this->set(
230
            'tree',
231
            $this->Entries->treeForNode($entry->get('tid'), ['root' => true])
0 ignored issues
show
Bug introduced by
Are you sure the usage of $this->Entries->treeForN... array('root' => true)) targeting App\Model\Table\EntriesTable::treeForNode() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
232
        );
233
        $this->Title->setFromPosting($entry);
234
235
        Stopwatch::stop('Entries->view()');
236
    }
237
238
    /**
239
     * Add new posting.
240
     *
241
     * @return void|\Cake\Network\Response
242
     */
243
    public function add()
244
    {
245
        $titleForPage = __('Write a New Posting');
246
        $this->set(compact('titleForPage'));
247
    }
248
249
    /**
250
     * Edit posting
251
     *
252
     * @param string $id posting-ID
253
     * @return void|\Cake\Network\Response
254
     * @throws NotFoundException
255
     * @throws BadRequestException
256
     */
257
    public function edit($id = null)
258
    {
259
        if (empty($id)) {
260
            throw new BadRequestException;
261
        }
262
263
        /** @var PostingInterface */
264
        $posting = $this->Entries->get($id);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $primaryKey of App\Model\Table\EntriesTable::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

264
        $posting = $this->Entries->get(/** @scrutinizer ignore-type */ $id);
Loading history...
265
        if (empty($posting)) {
266
            throw new NotFoundException;
267
        }
268
269
        if (!$posting->isEditingAllowed()) {
0 ignored issues
show
Bug introduced by
The method isEditingAllowed() does not exist on Cake\Datasource\EntityInterface. It seems like you code against a sub-type of Cake\Datasource\EntityInterface such as App\Model\Entity\User. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

269
        if (!$posting->/** @scrutinizer ignore-call */ isEditingAllowed()) {
Loading history...
270
            throw new SaitoForbiddenException(
271
                'Access to posting in EntriesController:edit() forbidden.',
272
                ['CurrentUser' => $this->CurrentUser]
273
            );
274
        }
275
276
        // show editing form
277
        if (!$posting->isEditingAsUserAllowed()) {
0 ignored issues
show
Bug introduced by
The method isEditingAsUserAllowed() does not exist on Cake\Datasource\EntityInterface. It seems like you code against a sub-type of Cake\Datasource\EntityInterface such as App\Model\Entity\User. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

277
        if (!$posting->/** @scrutinizer ignore-call */ isEditingAsUserAllowed()) {
Loading history...
278
            $this->Flash->set(
279
                __('notice_you_are_editing_as_mod'),
280
                ['element' => 'warning']
281
            );
282
        }
283
284
        $this->set(compact('posting'));
285
286
        // set headers
287
        $this->set(
288
            'headerSubnavLeftTitle',
289
            __('back_to_posting_from_linkname', $posting->get('name'))
290
        );
291
        $this->set('headerSubnavLeftUrl', ['action' => 'view', $id]);
292
        $this->set('form_title', __('edit_linkname'));
293
        $this->render('/Entries/add');
294
    }
295
296
    /**
297
     * Get thread-line to insert after an inline-answer
298
     *
299
     * @param string $id posting-ID
300
     * @return void|\Cake\Network\Response
301
     */
302
    public function threadLine($id = null)
303
    {
304
        $posting = $this->Entries->get($id);
0 ignored issues
show
Bug introduced by
It seems like $id can also be of type string; however, parameter $primaryKey of App\Model\Table\EntriesTable::get() does only seem to accept integer, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

304
        $posting = $this->Entries->get(/** @scrutinizer ignore-type */ $id);
Loading history...
305
        if (!$this->CurrentUser->getCategories()->permission('read', $posting->get('category'))) {
306
            return $this->_requireAuth();
307
        }
308
309
        $this->set('entrySub', $posting);
310
        // ajax requests so far are always answers
311
        $this->response = $this->response->withType('json');
312
        $this->set('level', '1');
313
    }
314
315
    /**
316
     * Delete posting
317
     *
318
     * @param string $id posting-ID
319
     * @return void
320
     * @throws NotFoundException
321
     * @throws MethodNotAllowedException
322
     */
323
    public function delete($id = null)
324
    {
325
        //$this->request->allowMethod(['post', 'delete']);
326
        if (!$id) {
327
            throw new NotFoundException;
328
        }
329
        /* @var Entry $posting */
330
        $posting = $this->Entries->get($id);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $primaryKey of App\Model\Table\EntriesTable::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

330
        $posting = $this->Entries->get(/** @scrutinizer ignore-type */ $id);
Loading history...
331
        if (!$posting) {
0 ignored issues
show
introduced by
$posting is of type App\Controller\Entry, thus it always evaluated to true.
Loading history...
332
            throw new NotFoundException;
333
        }
334
335
        $success = $this->Entries->treeDeleteNode($id);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $id of App\Model\Table\EntriesTable::treeDeleteNode(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

335
        $success = $this->Entries->treeDeleteNode(/** @scrutinizer ignore-type */ $id);
Loading history...
336
337
        if ($success) {
338
            $flashType = 'success';
339
            if ($posting->isRoot()) {
340
                $message = __('delete_tree_success');
341
                $redirect = '/';
342
            } else {
343
                $message = __('delete_subtree_success');
344
                $redirect = '/entries/view/' . $posting->get('pid');
345
            }
346
        } else {
347
            $flashType = 'error';
348
            $message = __('delete_tree_error');
349
            $redirect = $this->referer();
350
        }
351
        $this->Flash->set($message, ['element' => $flashType]);
352
        $this->redirect($redirect);
353
    }
354
355
    /**
356
     * Empty function for benchmarking
357
     *
358
     * @return void
359
     */
360
    public function e()
361
    {
362
        Stopwatch::start('Entries->e()');
363
        Stopwatch::stop('Entries->e()');
364
    }
365
366
    /**
367
     * Marks sub-entry $id as solution to its current root-entry
368
     *
369
     * @param string $id posting-ID
370
     * @return void
371
     * @throws BadRequestException
372
     */
373
    public function solve($id)
374
    {
375
        $this->autoRender = false;
376
        try {
377
            $posting = $this->Entries->get($id, ['return' => 'Entity']);
0 ignored issues
show
Bug introduced by
$id of type string is incompatible with the type integer expected by parameter $primaryKey of App\Model\Table\EntriesTable::get(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

377
            $posting = $this->Entries->get(/** @scrutinizer ignore-type */ $id, ['return' => 'Entity']);
Loading history...
378
379
            if (empty($posting)) {
380
                throw new \InvalidArgumentException('Posting to mark solved not found.');
381
            }
382
383
            if ($posting->isRoot()) {
0 ignored issues
show
Bug introduced by
The method isRoot() does not exist on Cake\Datasource\EntityInterface. It seems like you code against a sub-type of Cake\Datasource\EntityInterface such as App\Model\Entity\User or App\Model\Entity\Entry. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

383
            if ($posting->/** @scrutinizer ignore-call */ isRoot()) {
Loading history...
384
                throw new \InvalidArgumentException('Root postings cannot mark themself solved.');
385
            }
386
387
            $rootId = $posting->get('tid');
388
            $rootPosting = $this->Entries->get($rootId);
389
            if ($rootPosting->get('user_id') !== $this->CurrentUser->getId()) {
390
                throw new SaitoForbiddenException(
391
                    sprintf('Attempt to mark posting %s as solution.', $posting->get('id')),
392
                    ['CurrentUser' => $this->CurrentUser]
393
                );
394
            }
395
396
            $success = $this->Entries->toggleSolve($posting);
0 ignored issues
show
Bug introduced by
It seems like $posting can also be of type array; however, parameter $posting of App\Model\Table\EntriesTable::toggleSolve() does only seem to accept App\Model\Entity\Entry, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

396
            $success = $this->Entries->toggleSolve(/** @scrutinizer ignore-type */ $posting);
Loading history...
397
398
            if (!$success) {
399
                throw new BadRequestException;
400
            }
401
        } catch (\Exception $e) {
402
            throw new BadRequestException();
403
        }
404
    }
405
406
    /**
407
     * Merge threads.
408
     *
409
     * @param string $sourceId posting-ID of thread to be merged
410
     * @return void
411
     * @throws NotFoundException
412
     * @td put into admin entries controller
413
     */
414
    public function merge($sourceId = null)
415
    {
416
        if (!$sourceId) {
417
            throw new NotFoundException();
418
        }
419
420
        /* @var Entry */
421
        $posting = $this->Entries->findById($sourceId)->first();
0 ignored issues
show
Bug introduced by
The method findById() does not exist on App\Model\Table\EntriesTable. Since you implemented __call, consider adding a @method annotation. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

421
        $posting = $this->Entries->/** @scrutinizer ignore-call */ findById($sourceId)->first();
Loading history...
422
423
        if (!$posting || !$posting->isRoot()) {
424
            throw new NotFoundException();
425
        }
426
427
        // perform move operation
428
        $targetId = $this->request->getData('targetId');
429
        if (!empty($targetId)) {
430
            if ($this->Entries->threadMerge($sourceId, $targetId)) {
0 ignored issues
show
Bug introduced by
$targetId of type array|string is incompatible with the type integer expected by parameter $targetId of App\Model\Table\EntriesTable::threadMerge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

430
            if ($this->Entries->threadMerge($sourceId, /** @scrutinizer ignore-type */ $targetId)) {
Loading history...
Bug introduced by
$sourceId of type string is incompatible with the type integer expected by parameter $sourceId of App\Model\Table\EntriesTable::threadMerge(). ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

430
            if ($this->Entries->threadMerge(/** @scrutinizer ignore-type */ $sourceId, $targetId)) {
Loading history...
431
                $this->redirect('/entries/view/' . $sourceId);
432
433
                return;
434
            } else {
435
                $this->Flash->set(__('Error'), ['element' => 'error']);
436
            }
437
        }
438
439
        $this->viewBuilder()->setLayout('Admin.admin');
440
        $this->set(compact('posting'));
441
    }
442
443
    /**
444
     * Toggle posting property via ajax request.
445
     *
446
     * @param string $id posting-ID
447
     * @param string $toggle property
448
     *
449
     * @return \Cake\Network\Response
450
     */
451
    public function ajaxToggle($id = null, $toggle = null)
452
    {
453
        $allowed = ['fixed', 'locked'];
454
        if (!$id
455
            || !$toggle
456
            || !$this->request->is('ajax')
457
            || !in_array($toggle, $allowed)
458
        ) {
459
            throw new BadRequestException;
460
        }
461
462
        $current = $this->Entries->toggle((int)$id, $toggle);
463
        if ($current) {
464
            $out['html'] = __d('nondynamic', $toggle . '_unset_entry_link');
0 ignored issues
show
Comprehensibility Best Practice introduced by
$out was never initialized. Although not strictly required by PHP, it is generally a good practice to add $out = array(); before regardless.
Loading history...
465
        } else {
466
            $out['html'] = __d('nondynamic', $toggle . '_set_entry_link');
467
        }
468
469
        $this->response = $this->response->withType('json');
470
        $this->response = $this->response->withStringBody(json_encode($out));
471
472
        return $this->response;
473
    }
474
475
    /**
476
     * {@inheritDoc}
477
     */
478
    public function beforeFilter(Event $event)
479
    {
480
        parent::beforeFilter($event);
481
        Stopwatch::start('Entries->beforeFilter()');
482
483
        $this->Security->setConfig(
484
            'unlockedActions',
485
            ['solve', 'view']
486
        );
487
        $this->Authentication->allowUnauthenticated(['index', 'view', 'mix', 'update']);
488
489
        Stopwatch::stop('Entries->beforeFilter()');
490
    }
491
492
    /**
493
     * set view vars for category chooser
494
     *
495
     * @param CurrentUserInterface $User CurrentUser
496
     * @return void
497
     */
498
    protected function _setupCategoryChooser(CurrentUserInterface $User)
499
    {
500
        if (!$User->isLoggedIn()) {
501
            return;
502
        }
503
        $globalActivation = Configure::read(
504
            'Saito.Settings.category_chooser_global'
505
        );
506
        if (!$globalActivation) {
507
            if (!Configure::read(
508
                'Saito.Settings.category_chooser_user_override'
509
            )
510
            ) {
511
                return;
512
            }
513
            if (!$User->get('user_category_override')) {
514
                return;
515
            }
516
        }
517
518
        $this->set(
519
            'categoryChooserChecked',
520
            $User->getCategories()->getCustom('read')
521
        );
522
        switch ($User->getCategories()->getType()) {
523
            case 'single':
524
                $title = $User->get('user_category_active');
525
                break;
526
            case 'custom':
527
                $title = __('Custom');
528
                break;
529
            default:
530
                $title = __('All Categories');
531
        }
532
        $this->set('categoryChooserTitleId', $title);
533
        $this->set(
534
            'categoryChooser',
535
            $User->getCategories()->getAll('read', 'select')
536
        );
537
    }
538
539
    /**
540
     * Decide if an answering panel is show when rendering a posting
541
     *
542
     * @return void
543
     */
544
    protected function _showAnsweringPanel()
545
    {
546
        $showAnsweringPanel = false;
547
548
        if ($this->CurrentUser->isLoggedIn()) {
549
            // Only logged in users see the answering buttons if they …
550
            if (// … directly on entries/view but not inline
551
                ($this->request->getParam('action') === 'view' && !$this->request->is('ajax'))
552
                // … directly in entries/mix
553
                || $this->request->getParam('action') === 'mix'
554
                // … inline viewing … on entries/index.
555
                || ($this->Referer->wasController('entries')
556
                    && $this->Referer->wasAction('index'))
557
            ) {
558
                $showAnsweringPanel = true;
559
            }
560
        }
561
        $this->set('showAnsweringPanel', $showAnsweringPanel);
562
    }
563
564
    /**
565
     * makes root posting of $posting avaiable in view
566
     *
567
     * @param Posting $posting posting for root entry
568
     * @return void
569
     */
570
    protected function _setRootEntry(Posting $posting)
571
    {
572
        if (!$posting->isRoot()) {
573
            $root = $this->Entries->find()
574
                ->select(['user_id'])
575
                ->where(['id' => $posting->get('tid')])
576
                ->first();
577
        } else {
578
            $root = $posting;
579
        }
580
        $this->set('rootEntry', $root);
581
    }
582
}
583