Issues (326)

src/Controller/Component/ThreadsComponent.php (1 issue)

Severity
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 Saito\Posting\Basic\BasicPostingInterface;
21
use Saito\User\CurrentUser\CurrentUserInterface;
22
use Stopwatch\Lib\Stopwatch;
23
24
/**
25
 * Class ThreadsComponent
26
 *
27
 * @property PaginatorComponent $Paginator
28
 * @property AuthUserComponent $AuthUser
29
 */
30
class ThreadsComponent extends Component
31
{
32
    public $components = ['AuthUser', 'Paginator'];
33
34
    /**
35
     * Entries table
36
     *
37
     * @var EntriesTable
38
     */
39
    protected $Table;
40
41
    /**
42
     * {@inheritDoc}
43
     */
44
    public function initialize(array $config)
45
    {
46
        parent::initialize($config);
47
        $this->Table = $config['table'];
48
    }
49
50
    /**
51
     * Load paginated threads
52
     *
53
     * @param mixed $order order to apply
54
     * @param CurrentUserInterface $CurrentUser CurrentUser
55
     * @return array
56
     */
57
    public function paginate($order, CurrentUserInterface $CurrentUser): array
58
    {
59
        $initials = $this->paginateThreads($order, $CurrentUser);
60
        if (empty($initials)) {
61
            return [];
62
        }
63
64
        return $this->Table->postingsForThreads($initials, $order, $CurrentUser);
65
    }
66
67
    /**
68
     * Gets thread ids for paginated entries/index.
69
     *
70
     * @param array $order sort order
71
     * @param CurrentUserInterface $User current-user
72
     * @return array thread ids
73
     */
74
    protected function paginateThreads($order, CurrentUserInterface $User): array
75
    {
76
        Stopwatch::start('Entries->_getInitialThreads() Paginate');
77
        $categories = $User->getCategories()->getCurrent('read');
78
        if (empty($categories)) {
79
            // no readable categories for user (e.g. no public categories
80
            return [];
81
        }
82
83
        ////! Check DB performance after changing conditions/sorting!
84
        $customFinderOptions = [
85
            'conditions' => [
86
                'Entries.category_id IN' => $categories,
87
            ],
88
            // @td sanitize input?
89
            'limit' => Configure::read('Saito.Settings.topics_per_page'),
90
            'order' => $order,
91
            // Performance: Custom counter from categories counter-cache;
92
            // avoids a costly COUNT(*) DB call counting all pages for pagination.
93
            'counter' => function ($query) use ($categories) {
0 ignored issues
show
The parameter $query is not used and could be removed. ( Ignorable by Annotation )

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

93
            'counter' => function (/** @scrutinizer ignore-unused */ $query) use ($categories) {

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

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