Passed
Pull Request — master (#621)
by Tomas Norre
11:17
created

ProcessRepository::removeByProcessId()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 6
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 6
c 0
b 0
f 0
nc 1
nop 1
dl 0
loc 9
ccs 6
cts 6
cp 1
crap 1
rs 10
1
<?php
2
3
declare(strict_types=1);
4
5
namespace AOE\Crawler\Domain\Repository;
6
7
/***************************************************************
8
 *  Copyright notice
9
 *
10
 *  (c) 2019 AOE GmbH <[email protected]>
11
 *
12
 *  All rights reserved
13
 *
14
 *  This script is part of the TYPO3 project. The TYPO3 project is
15
 *  free software; you can redistribute it and/or modify
16
 *  it under the terms of the GNU General Public License as published by
17
 *  the Free Software Foundation; either version 3 of the License, or
18
 *  (at your option) any later version.
19
 *
20
 *  The GNU General Public License can be found at
21
 *  http://www.gnu.org/copyleft/gpl.html.
22
 *
23
 *  This script is distributed in the hope that it will be useful,
24
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
25
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
26
 *  GNU General Public License for more details.
27
 *
28
 *  This copyright notice MUST APPEAR in all copies of the script!
29
 ***************************************************************/
30
31
use AOE\Crawler\Configuration\ExtensionConfigurationProvider;
32
use AOE\Crawler\Domain\Model\Process;
33
use AOE\Crawler\Domain\Model\ProcessCollection;
34
use TYPO3\CMS\Core\Database\Connection;
35
use TYPO3\CMS\Core\Database\ConnectionPool;
36
use TYPO3\CMS\Core\Database\Query\QueryBuilder;
37
use TYPO3\CMS\Core\Utility\GeneralUtility;
38
use TYPO3\CMS\Extbase\Object\ObjectManager;
39
use TYPO3\CMS\Extbase\Persistence\Generic\QueryResult;
40
use TYPO3\CMS\Extbase\Persistence\QueryInterface;
41
use TYPO3\CMS\Extbase\Persistence\Repository;
42
43
/**
44
 * Class ProcessRepository
45
 *
46
 * @package AOE\Crawler\Domain\Repository
47
 */
48
class ProcessRepository extends Repository
49
{
50
    /**
51
     * @var string
52
     */
53
    protected $tableName = 'tx_crawler_process';
54
55
    /**
56
     * @var QueryBuilder
57
     */
58
    protected $queryBuilder;
59
60
    /**
61
     * @var array
62
     */
63
    protected $extensionSettings = [];
64
65
    /**
66
     * QueueRepository constructor.
67
     */
68 74
    public function __construct()
69
    {
70 74
        $objectManager = GeneralUtility::makeInstance(ObjectManager::class);
71 74
        parent::__construct($objectManager);
72
73 74
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
74
75
        /** @var ExtensionConfigurationProvider $configurationProvider */
76 74
        $configurationProvider = GeneralUtility::makeInstance(ExtensionConfigurationProvider::class);
77 74
        $this->extensionSettings = $configurationProvider->getExtensionConfiguration();
78 74
    }
79
80
    /**
81
     * This method is used to find all cli processes within a limit.
82
     */
83 7
    public function findAll(): ProcessCollection
84
    {
85
        /** @var ProcessCollection $collection */
86 7
        $collection = GeneralUtility::makeInstance(ProcessCollection::class);
87
88 7
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
89
90
        $queryBuilder
91 7
            ->select('*')
92 7
            ->from($this->tableName)
93 7
            ->orderBy('ttl', QueryInterface::ORDER_DESCENDING);
94
95
        /** @var Query $query */
96 7
        $query = $this->createQuery();
97 7
        $result = $query->statement($queryBuilder)->execute();
98
99
        /** @var Process $process */
100 7
        foreach ($result as $process) {
101 7
            $collection->append($process);
102
        }
103
104 7
        return $collection;
0 ignored issues
show
Bug Best Practice introduced by
The expression return $collection returns the type AOE\Crawler\Domain\Model\ProcessCollection which is incompatible with the return type mandated by TYPO3\CMS\Extbase\Persis...oryInterface::findAll() of TYPO3\CMS\Extbase\Persis...ryResultInterface|array.

In the issue above, the returned value is violating the contract defined by the mentioned interface.

Let's take a look at an example:

interface HasName {
    /** @return string */
    public function getName();
}

class Name {
    public $name;
}

class User implements HasName {
    /** @return string|Name */
    public function getName() {
        return new Name('foo'); // This is a violation of the ``HasName`` interface
                                // which only allows a string value to be returned.
    }
}
Loading history...
105
    }
106
107
    /**
108
     * @param string $processId
109
     */
110 1
    public function findByProcessId($processId)
111
    {
112 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
113
114
        return $queryBuilder
115 1
            ->select('*')
116 1
            ->from($this->tableName)
117 1
            ->where(
118 1
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId, \PDO::PARAM_STR))
119 1
            )->execute()->fetch(0);
120
    }
121
122 3
    public function findAllActive(): ProcessCollection
123
    {
124
        /** @var ProcessCollection $collection */
125 3
        $collection = GeneralUtility::makeInstance(ProcessCollection::class);
126
127 3
        $query = $this->createQuery();
128 3
        $query->setOrderings(['ttl' => QueryInterface::ORDER_DESCENDING]);
129 3
        $query->matching(
130 3
            $query->logicalAnd(
131 3
                $query->equals('active', 1),
132 3
                $query->equals('deleted', 0)
0 ignored issues
show
Unused Code introduced by
The call to TYPO3\CMS\Extbase\Persis...Interface::logicalAnd() has too many arguments starting with $query->equals('deleted', 0). ( Ignorable by Annotation )

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

132
            $query->/** @scrutinizer ignore-call */ 
133
                    logicalAnd(

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.

Loading history...
133
            )
134
        );
135
136
        /** @var QueryResult $result */
137 3
        $result = $query->execute();
138
139
        /** @var Process $process */
140 3
        foreach ($result as $process) {
141 3
            $collection->append($process);
142
        }
143
144 3
        return $collection;
145
    }
146
147
    /**
148
     * @param string $processId
149
     */
150 4
    public function removeByProcessId($processId): void
151
    {
152 4
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
153
154
        $queryBuilder
155 4
            ->delete($this->tableName)
156 4
            ->where(
157 4
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId, \PDO::PARAM_STR))
158 4
            )->execute();
159 4
    }
160
161
    /**
162
     * Returns the number of active processes.
163
     *
164
     * @return int
165
     * @deprecated Using ProcessRepository->countActive() is deprecated since 9.1.1 and will be removed in v11.x, please use ProcessRepository->findAllActive->count() instead
166
     */
167
    public function countActive()
168
    {
169
        return $this->findAllActive()->count();
170
    }
171
172
    /**
173
     * @return array|null
174
     *
175
     * Function is moved from ProcessCleanUpHook
176
     * TODO: Check why we need both getActiveProcessesOlderThanOneHour and getActiveOrphanProcesses, the get getActiveOrphanProcesses does not really check for Orphan in this implementation.
177
     */
178 1
    public function getActiveProcessesOlderThanOneHour()
179
    {
180 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
181 1
        $activeProcesses = [];
182
        $statement = $queryBuilder
183 1
            ->select('process_id', 'system_process_id')
184 1
            ->from($this->tableName)
185 1
            ->where(
186 1
                $queryBuilder->expr()->lte('ttl', intval(time() - $this->extensionSettings['processMaxRunTime'] - 3600)),
187 1
                $queryBuilder->expr()->eq('active', 1)
188
            )
189 1
            ->execute();
190
191 1
        while ($row = $statement->fetch()) {
192 1
            $activeProcesses[] = $row;
193
        }
194
195 1
        return $activeProcesses;
196
    }
197
198
    /**
199
     * Function is moved from ProcessCleanUpHook
200
     *
201
     * @return array
202
     * @see getActiveProcessesOlderThanOneHour
203
     */
204 1
    public function getActiveOrphanProcesses()
205
    {
206 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
207
208
        return $queryBuilder
209 1
            ->select('process_id', 'system_process_id')
210 1
            ->from($this->tableName)
211 1
            ->where(
212 1
                $queryBuilder->expr()->lte('ttl', intval(time() - $this->extensionSettings['processMaxRunTime'])),
213 1
                $queryBuilder->expr()->eq('active', 1)
214
            )
215 1
            ->execute()->fetchAll();
216
    }
217
218
    /**
219
     * Returns the number of processes that live longer than the given timestamp.
220
     */
221 1
    public function countNotTimeouted(int $ttl): int
222
    {
223 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
224
225
        return $queryBuilder
226 1
            ->count('*')
227 1
            ->from($this->tableName)
228 1
            ->where(
229 1
                $queryBuilder->expr()->eq('deleted', 0),
230 1
                $queryBuilder->expr()->gt('ttl', intval($ttl))
231
            )
232 1
            ->execute()
233 1
            ->fetchColumn(0);
234
    }
235
236
    /**
237
     * Get limit clause
238
     * @deprecated Using ProcessRepository::getLimitFromItemCountAndOffset() is deprecated since 9.1.1 and will be removed in v11.x, was not used, so will be removed
239
     */
240 4
    public static function getLimitFromItemCountAndOffset(int $itemCount, int $offset): string
241
    {
242 4
        $itemCount = filter_var($itemCount, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'default' => 20]]);
243 4
        $offset = filter_var($offset, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0, 'default' => 0]]);
244
245 4
        return $offset . ', ' . $itemCount;
246
    }
247
248 1
    public function deleteProcessesWithoutItemsAssigned(): void
249
    {
250 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
251
        $queryBuilder
252 1
            ->delete($this->tableName)
253 1
            ->where(
254 1
                $queryBuilder->expr()->eq('assigned_items_count', 0)
255
            )
256 1
            ->execute();
257 1
    }
258
259 1
    public function deleteProcessesMarkedAsDeleted(): void
260
    {
261 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
262
        $queryBuilder
263 1
            ->delete($this->tableName)
264 1
            ->where(
265 1
                $queryBuilder->expr()->eq('deleted', 1)
266
            )
267 1
            ->execute();
268 1
    }
269
270
    public function isProcessActive(string $processId): bool
271
    {
272
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
273
        $isActive = $queryBuilder
274
            ->select('active')
275
            ->from($this->tableName)
276
            ->where(
277
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId))
278
            )
279
            ->orderBy('ttl')
280
            ->execute()
281
            ->fetchColumn(0);
282
283
        return (bool) $isActive;
284
    }
285
286
    /**
287
     * @param $numberOfAffectedRows
288
     */
289 1
    public function updateProcessAssignItemsCount($numberOfAffectedRows, string $processId): void
290
    {
291 1
        GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->tableName)
292 1
            ->update(
293 1
                'tx_crawler_process',
294 1
                ['assigned_items_count' => (int) $numberOfAffectedRows],
295 1
                ['process_id' => $processId]
296
            );
297 1
    }
298
299 1
    public function markRequestedProcessesAsNotActive(array $processIds): void
300
    {
301 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
302 1
        $queryBuilder->update('tx_crawler_process')
303 1
            ->where(
304 1
                'NOT EXISTS (
305
                SELECT * FROM tx_crawler_queue
306
                    WHERE tx_crawler_queue.process_id = tx_crawler_process.process_id
307
                    AND tx_crawler_queue.exec_time = 0
308
                )',
309 1
                $queryBuilder->expr()->in('process_id', $queryBuilder->createNamedParameter($processIds, Connection::PARAM_STR_ARRAY)),
310 1
                $queryBuilder->expr()->eq('deleted', 0)
311
            )
312 1
            ->set('active', 0)
313 1
            ->execute();
314 1
    }
315
}
316