Completed
Push — master ( fd5325...d7e193 )
by Schlaefer
05:54 queued 03:00
created

ThreadsComponent::incrementViews()   B

Complexity

Conditions 6
Paths 5

Size

Total Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 6
nc 5
nop 2
dl 0
loc 27
rs 8.8657
c 0
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\Component;
14
15
use App\Model\Table\EntriesTable;
16
use Cake\Controller\Component;
17
use Cake\Controller\Component\PaginatorComponent;
18
use Cake\Core\Configure;
19
use Cake\ORM\Entity;
20
use Cake\ORM\TableRegistry;
21
use Saito\App\Registry;
22
use Saito\Posting\Posting;
23
use Saito\User\CurrentUser\CurrentUserInterface;
24
use Stopwatch\Lib\Stopwatch;
25
26
/**
27
 * Class ThreadsComponent
28
 *
29
 * @property PaginatorComponent $Paginator
30
 * @property AuthUserComponent $AuthUser
31
 */
32
class ThreadsComponent extends Component
33
{
34
35
    public $components = ['AuthUser', 'Paginator'];
36
37
    /**
38
     * Entries table
39
     *
40
     * @var EntriesTable
41
     */
42
    private $Entries;
43
44
    /**
45
     * Load paginated threads
46
     *
47
     * @param mixed $order order to apply
48
     * @return array
49
     */
50
    public function paginate($order)
51
    {
52
        /** @var EntriesTable */
53
        $EntriesTable = TableRegistry::getTableLocator()->get('Entries');
54
        $this->Entries = $EntriesTable;
55
56
        $CurrentUser = $this->_getCurrentUser();
57
        $initials = $this->_getInitialThreads($CurrentUser, $order);
58
        $threads = $this->Entries->treesForThreads($initials, $order);
59
60
        return $threads;
61
    }
62
63
    /**
64
     * Gets thread ids for paginated entries/index.
65
     *
66
     * @param CurrentUserInterface $User current-user
67
     * @param array $order sort order
68
     * @return array thread ids
69
     */
70
    protected function _getInitialThreads(CurrentUserInterface $User, $order)
71
    {
72
        Stopwatch::start('Entries->_getInitialThreads() Paginate');
73
        $categories = $User->getCategories()->getCurrent('read');
74
        if (empty($categories)) {
75
            // no readable categories for user (e.g. no public categories
76
            return [];
77
        }
78
79
        ////! Check DB performance after changing conditions/sorting!
80
        $customFinderOptions = [
81
            'conditions' => [
82
                'Entries.category_id IN' => $categories
83
            ],
84
            // @td sanitize input?
85
            'limit' => Configure::read('Saito.Settings.topics_per_page'),
86
            'order' => $order,
87
            // Performance: Custom counter from categories counter-cache;
88
            // avoids a costly COUNT(*) DB call counting all pages for pagination.
89
            'counter' => function ($query) use ($categories) {
0 ignored issues
show
Unused Code introduced by
The parameter $query is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
90
                $results = $this->Entries->Categories->find('all')
91
                ->select(['thread_count'])
92
                ->where(['id IN' => $categories])
93
                ->all();
94
                $count = array_reduce(
95
                    $results->toArray(),
96
                    function ($carry, Entity $entity) {
97
                        return $carry + $entity->get('thread_count');
98
                    },
99
                    0
100
                );
101
102
                return $count;
103
            }
104
        ];
105
106
        $settings = [
107
            'finder' => ['indexPaginator' => $customFinderOptions],
108
        ];
109
110
        // use setConfig on Component to not merge but overwrite/set the config
111
        $this->Paginator->setConfig('whitelist', ['page'], false);
112
        $initialThreads = $this->Paginator->paginate($this->Entries, $settings);
113
114
        $initialThreadsNew = [];
115
        foreach ($initialThreads as $k => $v) {
116
            $initialThreadsNew[$k] = $v['id'];
117
        }
118
        Stopwatch::stop('Entries->_getInitialThreads() Paginate');
119
120
        return $initialThreadsNew;
121
    }
122
123
    /**
124
     * Increment views for posting if posting doesn't belong to current user.
125
     *
126
     * @param Posting $posting posting
127
     * @param string $type type
128
     * - 'null' increment single posting
129
     * - 'thread' increment all postings in thread
130
     *
131
     * @return void
132
     */
133
    public function incrementViews(Posting $posting, $type = null)
134
    {
135
        if ($this->AuthUser->isBot()) {
136
            return;
137
        }
138
139
        /** @var EntriesTable */
140
        $Entries = TableRegistry::getTableLocator()->get('Entries');
141
        $CurrentUser = $this->_getCurrentUser();
142
143
        if ($type === 'thread') {
144
            $where = ['tid' => $posting->get('tid')];
145
            if ($CurrentUser->isLoggedIn()) {
146
                $where['user_id !='] = $CurrentUser->getId();
147
            }
148
            $Entries->increment($where, 'views');
149
150
            return;
151
        }
152
153
        if ($CurrentUser->isLoggedIn()
154
            && ($posting->get('user_id') === $CurrentUser->getId())) {
155
            return;
156
        }
157
158
        $Entries->increment($posting->get('id'), 'views');
159
    }
160
161
    /**
162
     * Get CurrentUser
163
     *
164
     * @return CurrentUserInterface
165
     */
166
    protected function _getCurrentUser(): CurrentUserInterface
167
    {
168
        /** @var CurrentUserInterface */
169
        $CU = Registry::get('CU');
170
171
        return $CU;
172
    }
173
}
174