Passed
Push — main ( 25a0e5...cb124e )
by Tomas Norre
26:12 queued 11:36
created

ProcessRepository::addProcess()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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