Passed
Push — cleanup/crawlercontroller ( c98170...0af167 )
by Tomas Norre
06:32
created

markRequestedProcessesAsNotActive()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 15
Code Lines 12

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 9
CRAP Score 1

Importance

Changes 0
Metric Value
cc 1
eloc 12
nc 1
nop 1
dl 0
loc 15
ccs 9
cts 9
cp 1
crap 1
rs 9.8666
c 0
b 0
f 0
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
39
/**
40
 * Class ProcessRepository
41
 *
42
 * @package AOE\Crawler\Domain\Repository
43
 */
44
class ProcessRepository extends AbstractRepository
45
{
46
    /**
47
     * @var string
48
     */
49
    protected $tableName = 'tx_crawler_process';
50
51
    /**
52
     * @var QueryBuilder
53
     */
54
    protected $queryBuilder;
55
56
    /**
57
     * @var array
58
     */
59
    protected $extensionSettings = [];
60
61
    /**
62
     * QueueRepository constructor.
63
     */
64 62
    public function __construct()
65
    {
66 62
        $this->queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
67
68
        /** @var ExtensionConfigurationProvider $configurationProvider */
69 62
        $configurationProvider = GeneralUtility::makeInstance(ExtensionConfigurationProvider::class);
70 62
        $this->extensionSettings = $configurationProvider->getExtensionConfiguration();
71 62
    }
72
73
    /**
74
     * This method is used to find all cli processes within a limit.
75
     *
76
     * @return ProcessCollection
77
     */
78 2
    public function findAll(): ProcessCollection
79
    {
80
        /** @var ProcessCollection $collection */
81 2
        $collection = GeneralUtility::makeInstance(ProcessCollection::class);
82 2
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
83
84
        $statement = $queryBuilder
85 2
            ->select('*')
86 2
            ->from($this->tableName)
87 2
            ->orderBy('ttl', 'DESC')
88 2
            ->execute();
89
90 2
        while ($row = $statement->fetch()) {
91 2
            $process = GeneralUtility::makeInstance(Process::class);
92 2
            $process->setProcessId($row['process_id']);
93 2
            $process->setActive($row['active']);
94 2
            $process->setTtl($row['ttl']);
95 2
            $process->setAssignedItemsCount($row['assigned_items_count']);
96 2
            $process->setDeleted($row['deleted']);
97 2
            $process->setSystemProcessId($row['system_process_id']);
98 2
            $collection->append($process);
99
        }
100
101 2
        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...
102
    }
103
104
    /**
105
     * @param string $processId
106
     * @return mixed
107
     */
108 1
    public function findByProcessId($processId)
109
    {
110 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
111
112
        return $queryBuilder
113 1
            ->select('*')
114 1
            ->from($this->tableName)
115 1
            ->where(
116 1
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId, \PDO::PARAM_STR))
117 1
            )->execute()->fetch(0);
118
    }
119
120
    /**
121
     * @return ProcessCollection
122
     */
123 1
    public function findAllActive(): ProcessCollection
124
    {
125
        /** @var ProcessCollection $collection */
126 1
        $collection = GeneralUtility::makeInstance(ProcessCollection::class);
127 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
128
129
        $statement = $queryBuilder
130 1
            ->select('*')
131 1
            ->from($this->tableName)
132 1
            ->where(
133 1
                $queryBuilder->expr()->eq('active', 1),
134 1
                $queryBuilder->expr()->eq('deleted', 0)
135
            )
136 1
            ->orderBy('ttl', 'DESC')
137 1
            ->execute();
138
139 1
        while ($row = $statement->fetch()) {
140 1
            $process = new Process();
141 1
            $process->setProcessId($row['process_id']);
142 1
            $process->setActive($row['active']);
143 1
            $process->setTtl($row['ttl']);
144 1
            $process->setAssignedItemsCount($row['assigned_items_count']);
145 1
            $process->setDeleted($row['deleted']);
146 1
            $process->setSystemProcessId($row['system_process_id']);
147 1
            $collection->append($process);
148
        }
149
150 1
        return $collection;
151
    }
152
153
    /**
154
     * @param string $processId
155
     *
156
     * @return void
157
     */
158 4
    public function removeByProcessId($processId): void
159
    {
160 4
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
161
162
        $queryBuilder
163 4
            ->delete($this->tableName)
164 4
            ->where(
165 4
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId, \PDO::PARAM_STR))
166 4
            )->execute();
167 4
    }
168
169
    /**
170
     * Returns the number of active processes.
171
     *
172
     * @return int
173
     */
174 2
    public function countActive()
175
    {
176 2
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
177
178
        return $queryBuilder
179 2
            ->count('*')
180 2
            ->from($this->tableName)
181 2
            ->where(
182 2
                $queryBuilder->expr()->eq('active', 1),
183 2
                $queryBuilder->expr()->eq('deleted', 0)
184
            )
185 2
            ->execute()
186 2
            ->fetchColumn(0);
187
    }
188
189
    /**
190
     * @return array|null
191
     *
192
     * Function is moved from ProcessCleanUpHook
193
     * TODO: Check why we need both getActiveProcessesOlderThanOneHour and getActiveOrphanProcesses, the get getActiveOrphanProcesses does not really check for Orphan in this implementation.
194
     */
195 1
    public function getActiveProcessesOlderThanOneHour()
196
    {
197 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
198 1
        $activeProcesses = [];
199
        $statement = $queryBuilder
200 1
            ->select('process_id', 'system_process_id')
201 1
            ->from($this->tableName)
202 1
            ->where(
203 1
                $queryBuilder->expr()->lte('ttl', intval(time() - $this->extensionSettings['processMaxRunTime'] - 3600)),
204 1
                $queryBuilder->expr()->eq('active', 1)
205
            )
206 1
            ->execute();
207
208 1
        while ($row = $statement->fetch()) {
209 1
            $activeProcesses[] = $row;
210
        }
211
212 1
        return $activeProcesses;
213
    }
214
215
    /**
216
     * Function is moved from ProcessCleanUpHook
217
     *
218
     * @return array
219
     * @see getActiveProcessesOlderThanOneHour
220
     */
221 1
    public function getActiveOrphanProcesses()
222
    {
223 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
224
225
        return $queryBuilder
226 1
            ->select('process_id', 'system_process_id')
227 1
            ->from($this->tableName)
228 1
            ->where(
229 1
                $queryBuilder->expr()->lte('ttl', intval(time() - $this->extensionSettings['processMaxRunTime'])),
230 1
                $queryBuilder->expr()->eq('active', 1)
231
            )
232 1
            ->execute()->fetchAll();
233
    }
234
235
    /**
236
     * Returns the number of processes that live longer than the given timestamp.
237
     */
238 1
    public function countNotTimeouted(int $ttl): int
239
    {
240 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
241
242
        return $queryBuilder
243 1
            ->count('*')
244 1
            ->from($this->tableName)
245 1
            ->where(
246 1
                $queryBuilder->expr()->eq('deleted', 0),
247 1
                $queryBuilder->expr()->gt('ttl', intval($ttl))
248
            )
249 1
            ->execute()
250 1
            ->fetchColumn(0);
251
    }
252
253
    /**
254
     * Get limit clause
255
     */
256 4
    public static function getLimitFromItemCountAndOffset(int $itemCount, int $offset): string
257
    {
258 4
        $itemCount = filter_var($itemCount, FILTER_VALIDATE_INT, ['options' => ['min_range' => 1, 'default' => 20]]);
259 4
        $offset = filter_var($offset, FILTER_VALIDATE_INT, ['options' => ['min_range' => 0, 'default' => 0]]);
260
261 4
        return $offset . ', ' . $itemCount;
262
    }
263
264
    /**
265
     * @return void
266
     */
267 1
    public function deleteProcessesWithoutItemsAssigned(): void
268
    {
269 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
270
        $queryBuilder
271 1
            ->delete($this->tableName)
272 1
            ->where(
273 1
                $queryBuilder->expr()->eq('assigned_items_count', 0)
274
            )
275 1
            ->execute();
276 1
    }
277
278 1
    public function deleteProcessesMarkedAsDeleted(): void
279
    {
280 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
281
        $queryBuilder
282 1
            ->delete($this->tableName)
283 1
            ->where(
284 1
                $queryBuilder->expr()->eq('deleted', 1)
285
            )
286 1
            ->execute();
287 1
    }
288
289
    public function isProcessActive(string $processId): bool
290
    {
291
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
292
        $isActive = $queryBuilder
293
            ->select('active')
294
            ->from($this->tableName)
295
            ->where(
296
                $queryBuilder->expr()->eq('process_id', $queryBuilder->createNamedParameter($processId))
297
            )
298
            ->orderBy('ttl')
299
            ->execute()
300
            ->fetchColumn(0);
301
302
        return (bool)$isActive;
303
    }
304
305
    /**
306
     * @param $numberOfAffectedRows
307
     * @param string $processId
308
     */
309 1
    public function updateProcessAssignItemsCount($numberOfAffectedRows, string $processId): void
310
    {
311 1
        GeneralUtility::makeInstance(ConnectionPool::class)->getConnectionForTable($this->tableName)
312 1
            ->update(
313 1
                'tx_crawler_process',
314 1
                ['assigned_items_count' => (int)$numberOfAffectedRows],
315 1
                ['process_id' => $processId]
316
            );
317 1
    }
318
319 1
    public function markRequestedProcessesAsNotActive(array $processIds): void
320
    {
321 1
        $queryBuilder = GeneralUtility::makeInstance(ConnectionPool::class)->getQueryBuilderForTable($this->tableName);
322 1
        $queryBuilder->update('tx_crawler_process')
323 1
            ->where(
324 1
                'NOT EXISTS (
325
                SELECT * FROM tx_crawler_queue
326
                    WHERE tx_crawler_queue.process_id = tx_crawler_process.process_id
327
                    AND tx_crawler_queue.exec_time = 0
328
                )',
329 1
                $queryBuilder->expr()->in('process_id', $queryBuilder->createNamedParameter($processIds, Connection::PARAM_STR_ARRAY)),
330 1
                $queryBuilder->expr()->eq('deleted', 0)
331
            )
332 1
            ->set('active', 0)
333 1
            ->execute();
334 1
    }
335
}
336