Passed
Push — cleanup/crawlercontroller-cli-... ( 1c5632...d0938c )
by Tomas Norre
06:15
created

ProcessRepository   A

Complexity

Total Complexity 17

Size/Duplication

Total Lines 272
Duplicated Lines 0 %

Test Coverage

Coverage 92.19%

Importance

Changes 0
Metric Value
eloc 125
dl 0
loc 272
ccs 118
cts 128
cp 0.9219
rs 10
c 0
b 0
f 0
wmc 17

14 Methods

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