Passed
Push — master ( 6aab4a...f2ba87 )
by
unknown
17:34
created

LogEntryRepository::injectQuerySettings()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 1
dl 0
loc 3
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
1
<?php
2
3
declare(strict_types=1);
4
5
/*
6
 * This file is part of the TYPO3 CMS project.
7
 *
8
 * It is free software; you can redistribute it and/or modify it under
9
 * the terms of the GNU General Public License, either version 2
10
 * of the License, or any later version.
11
 *
12
 * For the full copyright and license information, please read the
13
 * LICENSE.txt file that was distributed with this source code.
14
 *
15
 * The TYPO3 project - inspiring people to share!
16
 */
17
18
namespace TYPO3\CMS\Belog\Domain\Repository;
19
20
use TYPO3\CMS\Backend\Tree\View\PageTreeView;
21
use TYPO3\CMS\Belog\Domain\Model\Constraint;
22
use TYPO3\CMS\Belog\Domain\Model\LogEntry;
23
use TYPO3\CMS\Belog\Domain\Model\Workspace;
24
use TYPO3\CMS\Core\Authentication\GroupResolver;
25
use TYPO3\CMS\Core\Database\ConnectionPool;
26
use TYPO3\CMS\Core\Type\Bitmask\Permission;
27
use TYPO3\CMS\Core\Utility\GeneralUtility;
28
use TYPO3\CMS\Extbase\Persistence\Generic\Qom\ConstraintInterface;
29
use TYPO3\CMS\Extbase\Persistence\Generic\QuerySettingsInterface;
30
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
31
use TYPO3\CMS\Extbase\Persistence\QueryResultInterface;
32
use TYPO3\CMS\Extbase\Persistence\Repository;
33
34
/**
35
 * Sys log entry repository
36
 * @internal This class is a TYPO3 Backend implementation and is not considered part of the Public TYPO3 API.
37
 */
38
class LogEntryRepository extends Repository
39
{
40
    public ?QuerySettingsInterface $querySettings = null;
41
42
    /**
43
     * @param QuerySettingsInterface $querySettings
44
     */
45
    public function injectQuerySettings(QuerySettingsInterface $querySettings): void
46
    {
47
        $this->querySettings = $querySettings;
48
    }
49
50
    /**
51
     * Initialize some local variables to be used during creation of objects
52
     */
53
    public function initializeObject(): void
54
    {
55
        $this->setDefaultQuerySettings($this->querySettings->setRespectStoragePage(false));
0 ignored issues
show
Bug introduced by
The method setRespectStoragePage() does not exist on null. ( Ignorable by Annotation )

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

55
        $this->setDefaultQuerySettings($this->querySettings->/** @scrutinizer ignore-call */ setRespectStoragePage(false));

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
56
    }
57
58
    /**
59
     * Finds all log entries that match all given constraints.
60
     *
61
     * @param Constraint $constraint
62
     * @return QueryResultInterface
63
     */
64
    public function findByConstraint(Constraint $constraint): QueryResultInterface
65
    {
66
        $query = $this->createQuery();
67
        $queryConstraints = $this->createQueryConstraints($query, $constraint);
68
        if (!empty($queryConstraints)) {
69
            $query->matching($query->logicalAnd($queryConstraints));
70
        }
71
        $query->setOrderings(['uid' => QueryInterface::ORDER_DESCENDING]);
72
        $query->setLimit($constraint->getNumber());
73
        return $query->execute();
0 ignored issues
show
Bug Best Practice introduced by
The expression return $query->execute() could return the type array which is incompatible with the type-hinted return TYPO3\CMS\Extbase\Persistence\QueryResultInterface. Consider adding an additional type-check to rule them out.
Loading history...
74
    }
75
76
    /**
77
     * Create an array of query constraints from constraint object
78
     *
79
     * @param QueryInterface $query
80
     * @param Constraint $constraint
81
     * @return ConstraintInterface[]
82
     */
83
    protected function createQueryConstraints(QueryInterface $query, Constraint $constraint): array
84
    {
85
        $queryConstraints = [];
86
        // User / group handling
87
        $this->addUsersAndGroupsToQueryConstraints($constraint, $query, $queryConstraints);
88
        // Workspace
89
        if ((int)$constraint->getWorkspaceUid() !== Workspace::UID_ANY_WORKSPACE) {
90
            $queryConstraints[] = $query->equals('workspace', $constraint->getWorkspaceUid());
91
        }
92
        // Action (type):
93
        if ($constraint->getAction() > 0) {
94
            $queryConstraints[] = $query->equals('type', $constraint->getAction());
95
        } elseif ($constraint->getAction() === -1) {
96
            $queryConstraints[] = $query->equals('type', 5);
97
        }
98
        // Start / endtime handling: The timestamp calculation was already done
99
        // in the controller, since we need those calculated values in the view as well.
100
        $queryConstraints[] = $query->greaterThanOrEqual('tstamp', $constraint->getStartTimestamp());
101
        $queryConstraints[] = $query->lessThan('tstamp', $constraint->getEndTimestamp());
102
        // Page and level constraint if in page context
103
        $this->addPageTreeConstraintsToQuery($constraint, $query, $queryConstraints);
104
        return $queryConstraints;
105
    }
106
107
    /**
108
     * Adds constraints for the page(s) to the query; this could be one single page or a whole subtree beneath a given
109
     * page.
110
     *
111
     * @param Constraint $constraint
112
     * @param QueryInterface $query
113
     * @param array $queryConstraints the query constraints to add to, will be modified
114
     */
115
    protected function addPageTreeConstraintsToQuery(
116
        Constraint $constraint,
117
        QueryInterface $query,
118
        array &$queryConstraints
119
    ): void {
120
        $pageIds = [];
121
        // Check if we should get a whole tree of pages and not only a single page
122
        if ($constraint->getDepth() > 0) {
123
            /** @var \TYPO3\CMS\Backend\Tree\View\PageTreeView $pageTree */
124
            $pageTree = GeneralUtility::makeInstance(PageTreeView::class);
125
            $pageTree->init('AND ' . $GLOBALS['BE_USER']->getPagePermsClause(Permission::PAGE_SHOW));
126
            $pageTree->makeHTML = 0;
127
            $pageTree->fieldArray = ['uid'];
128
            $pageTree->getTree($constraint->getPageId(), $constraint->getDepth());
129
            $pageIds = $pageTree->ids;
130
        }
131
        if (!empty($constraint->getPageId())) {
132
            $pageIds[] = $constraint->getPageId();
133
        }
134
        if (!empty($pageIds)) {
135
            $queryConstraints[] = $query->in('eventPid', $pageIds);
136
        }
137
    }
138
139
    /**
140
     * Adds users and groups to the query constraints.
141
     *
142
     * @param Constraint $constraint
143
     * @param QueryInterface $query
144
     * @param array $queryConstraints the query constraints to add to, will be modified
145
     */
146
    protected function addUsersAndGroupsToQueryConstraints(
147
        Constraint $constraint,
148
        QueryInterface $query,
149
        array &$queryConstraints
150
    ): void {
151
        $userOrGroup = $constraint->getUserOrGroup();
152
        if ($userOrGroup === '') {
153
            return;
154
        }
155
        // Constraint for a group
156
        if (strpos($userOrGroup, 'gr-') === 0) {
157
            $groupId = (int)substr($userOrGroup, 3);
158
            $groupResolver = GeneralUtility::makeInstance(GroupResolver::class);
159
            $userIds = $groupResolver->findAllUsersInGroups([$groupId], 'be_groups', 'be_users');
160
            if (!empty($userIds)) {
161
                $userIds = array_column($userIds, 'uid');
162
                $userIds = array_map('intval', $userIds);
163
                $queryConstraints[] = $query->in('userid', $userIds);
164
            } else {
165
                // If there are no group members -> use -1 as constraint to not find anything
166
                $queryConstraints[] = $query->in('userid', [-1]);
167
            }
168
        } elseif (strpos($userOrGroup, 'us-') === 0) {
169
            $queryConstraints[] = $query->equals('userid', (int)substr($userOrGroup, 3));
170
        } elseif ($userOrGroup === '-1') {
171
            $queryConstraints[] = $query->equals('userid', (int)$GLOBALS['BE_USER']->user['uid']);
172
        }
173
    }
174
175
    /**
176
     * Deletes all messages which have the same message details
177
     *
178
     * @param LogEntry $logEntry
179
     * @return int
180
     */
181
    public function deleteByMessageDetails(LogEntry $logEntry): int
182
    {
183
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)
184
            ->getQueryBuilderForTable('sys_log');
185
        $constraints = [];
186
        $constraints[] = $queryBuilder->expr()->eq('details', $queryBuilder->createNamedParameter($logEntry->getDetails()));
187
        // If the detailsNo is 11 or 12 we got messages that are heavily using placeholders. In this case
188
        // we need to compare both the message and the actual log data to not remove too many log entries.
189
        if (GeneralUtility::inList('11,12', (string)$logEntry->getDetailsNumber())) {
190
            $constraints[] = $queryBuilder->expr()->eq('log_data', $queryBuilder->createNamedParameter($logEntry->getLogData()));
191
        }
192
        return $queryBuilder->delete('sys_log')
193
            ->where(...$constraints)
194
            ->execute();
195
    }
196
}
197