• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

tomasnorre / crawler / 24795022127

22 Apr 2026 06:17PM UTC coverage: 68.791%. Remained the same
24795022127

push

github

web-flow
[TASK] Remove obsolete ?? operator (#1278)

0 of 1 new or added line in 1 file covered. (0.0%)

1900 of 2762 relevant lines covered (68.79%)

3.16 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Classes/Controller/Backend/BackendModuleStartCrawlingController.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace AOE\Crawler\Controller\Backend;
6

7
/*
8
 * (c) 2022-     Tomas Norre Mikkelsen <tomasnorre@gmail.com>
9
 *
10
 * This file is part of the TYPO3 Crawler Extension.
11
 *
12
 * It is free software; you can redistribute it and/or modify it under
13
 * the terms of the GNU General Public License, either version 2
14
 * of the License, or any later version.
15
 *
16
 * For the full copyright and license information, please read the
17
 * LICENSE.txt file that was distributed with this source code.
18
 *
19
 * The TYPO3 project - inspiring people to share!
20
 */
21

22
use AOE\Crawler\Controller\Backend\Helper\RequestHelper;
23
use AOE\Crawler\Controller\Backend\Helper\UrlBuilder;
24
use AOE\Crawler\Controller\CrawlerController;
25
use AOE\Crawler\Domain\Model\Reason;
26
use AOE\Crawler\Event\InvokeQueueChangeEvent;
27
use AOE\Crawler\Utility\MessageUtility;
28
use Psr\Http\Message\ResponseInterface;
29
use Psr\Http\Message\ServerRequestInterface;
30
use Psr\Http\Message\UriInterface;
31
use Symfony\Contracts\Service\Attribute\Required;
32
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
33
use TYPO3\CMS\Backend\Routing\UriBuilder;
34
use TYPO3\CMS\Backend\Template\ModuleTemplate;
35
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
36
use TYPO3\CMS\Core\Utility\GeneralUtility;
37

38
/**
39
 * @internal since v12.0.0
40
 */
41
class BackendModuleStartCrawlingController extends AbstractBackendModuleController implements BackendModuleControllerInterface
42
{
43
    private const BACKEND_MODULE = 'web_site_crawler_start';
44
    private const LINE_FEED = 10;
45
    private const CARRIAGE_RETURN = 13;
46
    private int $reqMinute = 1000;
47
    private EventDispatcher $eventDispatcher;
48

49
    /**
50
     * @var array holds the selection of configuration from the configuration selector box
51
     */
52
    private $incomingConfigurationSelection = [];
53

54
    public function __construct(
55
        private readonly CrawlerController $crawlerController,
56
        private readonly UriBuilder $backendUriBuilder,
57
    ) {
58
    }
×
59

60
    #[Required]
61
    public function setEventDispatcher(): void
62
    {
63
        $this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcher::class);
×
64
    }
65

66
    #[\Override]
67
    public function handleRequest(ServerRequestInterface $request): ResponseInterface
68
    {
69
        $this->makeCrawlerProcessableChecks($this->extensionSettings);
×
70
        $this->pageUid = (int) ($request->getQueryParams()['id'] ?? -1);
×
71
        $this->moduleTemplate = $this->setupView($request, $this->pageUid);
×
72
        $this->moduleTemplate->makeDocHeaderModuleMenu([
×
73
            'id' => $request->getQueryParams()['id'] ?? -1,
×
74
        ]);
×
75

76
        $this->assignValues($request);
×
77
        return $this->moduleTemplate->renderResponse('Backend/ShowCrawlerInformation');
×
78
    }
79

80
    private function assignValues(ServerRequestInterface $request): ModuleTemplate
81
    {
82
        $logUrl = $this->backendUriBuilder->buildUriFromRoute('web_site_crawler_log', [
×
83
            'id' => $this->pageUid,
×
84
        ]);
×
85

86
        $crawlingDepth = RequestHelper::getIntFromRequest($request, 'crawlingDepth');
×
87
        $submitCrawlUrls = RequestHelper::getBoolFromRequest($request, '_crawl');
×
88
        $downloadCrawlUrls = RequestHelper::getBoolFromRequest($request, '_download');
×
89
        $scheduledTime = $this->getScheduledTime(RequestHelper::getStringFromRequest($request, 'tstamp', 'now'));
×
90

91
        $this->incomingConfigurationSelection = RequestHelper::getArrayFromRequest($request, 'configurationSelection');
×
92

93
        //$this->crawlerController = $this->getCrawlerController();
94
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
×
95

96
        $queueRows = '';
×
97
        $noConfigurationSelected = $this->isNoConfigurationSelected();
×
98
        if ($noConfigurationSelected) {
×
99
            MessageUtility::addWarningMessage(
×
100
                $this->getLanguageService()->sL(
×
101
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.noConfigSelected'
×
102
                )
×
103
            );
×
104
        } else {
105
            if ($submitCrawlUrls) {
×
106
                $reason = new Reason();
×
107
                $reason->setReason(Reason::REASON_GUI_SUBMIT);
×
108
                $reason->setDetailText(
×
109
                    'The user ' . $GLOBALS['BE_USER']->user['username'] . ' added pages to the crawler queue manually'
×
110
                );
×
111
                $this->eventDispatcher->dispatch(new InvokeQueueChangeEvent($reason));
×
112
            }
113

114
            $queueRows = $this->crawlerController->getPageTreeAndUrls(
×
115
                $this->pageUid,
×
116
                $crawlingDepth,
×
117
                $scheduledTime,
×
118
                $this->reqMinute,
×
119
                $submitCrawlUrls,
×
120
                $downloadCrawlUrls,
×
121
                // Do not filter any processing instructions
122
                [],
×
123
                $this->incomingConfigurationSelection
×
124
            );
×
125
        }
126

127
        // Download Urls to crawl:
128
        $downloadUrls = $this->crawlerController->downloadUrls;
×
129
        if ($downloadCrawlUrls) {
×
130
            // Creating output header:
131
            header('Content-Type: application/octet-stream');
×
132
            header('Content-Disposition: attachment; filename=CrawlerUrls.txt');
×
133

134
            // Printing the content of the CSV lines:
135
            echo implode(chr(self::CARRIAGE_RETURN) . chr(self::LINE_FEED), $downloadUrls);
×
136
            exit;
×
137
        }
138

139
        return $this->moduleTemplate->assignMultiple([
×
140
            'currentPageId' => $this->pageUid,
×
141
            'noConfigurationSelected' => $noConfigurationSelected,
×
142
            'submitCrawlUrls' => $submitCrawlUrls,
×
NEW
143
            'amountOfUrls' => count($this->crawlerController->duplicateTrack),
×
144
            'selectors' => $this->generateConfigurationSelectors($this->pageUid, (string) $crawlingDepth, $request),
×
145
            'queueRows' => $queueRows,
×
146
            'displayActions' => 0,
×
147
            'actionUrl' => $this->getActionUrl(),
×
148
            'logUrl' => $logUrl,
×
149
        ]);
×
150
    }
151

152
    /**
153
     * Generates the configuration selectors for compiling URLs:
154
     */
155
    private function generateConfigurationSelectors(
156
        int $pageId,
157
        string $crawlingDepth,
158
        ServerRequestInterface $request
159
    ): array {
160
        $selectors = [];
×
161
        $selectors['depth'] = $this->selectorBox(
×
162
            [
×
163
                0 => $this->getLanguageService()->sL(
×
164
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_0'
×
165
                ),
×
166
                1 => $this->getLanguageService()->sL(
×
167
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_1'
×
168
                ),
×
169
                2 => $this->getLanguageService()->sL(
×
170
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_2'
×
171
                ),
×
172
                3 => $this->getLanguageService()->sL(
×
173
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_3'
×
174
                ),
×
175
                4 => $this->getLanguageService()->sL(
×
176
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_4'
×
177
                ),
×
178
                99 => $this->getLanguageService()->sL(
×
179
                    'LLL:EXT:core/Resources/Private/Language/locallang_core.xlf:labels.depth_infi'
×
180
                ),
×
181
            ],
×
182
            'crawlingDepth',
×
183
            $crawlingDepth,
×
184
            false
×
185
        );
×
186

187
        // Configurations
188
        $availableConfigurations = $this->crawlerController->getConfigurationsForBranch(
×
189
            $pageId,
×
190
            (int) $crawlingDepth,
×
191
        );
×
192
        $selectors['configurations'] = $this->selectorBox(
×
193
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
×
194
            'configurationSelection',
×
195
            $this->incomingConfigurationSelection,
×
196
            true
×
197
        );
×
198

199
        // Scheduled time:
200
        $selectors['scheduled'] = $this->selectorBox(
×
201
            [
×
202
                'now' => $this->getLanguageService()->sL(
×
203
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.now'
×
204
                ),
×
205
                'midnight' => $this->getLanguageService()->sL(
×
206
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.midnight'
×
207
                ),
×
208
                '04:00' => $this->getLanguageService()->sL(
×
209
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.4am'
×
210
                ),
×
211
            ],
×
212
            'tstamp',
×
213
            RequestHelper::getStringFromRequest($request, 'tstamp', 'now'),
×
214
            false
×
215
        );
×
216

217
        return $selectors;
×
218
    }
219

220
    /**
221
     * Create selector box
222
     *
223
     * @param array $optArray Options key(value) => label pairs
224
     * @param string $name Selector box name
225
     * @param string|array|null $value Selector box value (array for multiple...)
226
     * @param boolean $multiple If set, will draw multiple box.
227
     *
228
     * @return string HTML select element
229
     */
230
    private function selectorBox($optArray, $name, string|array|null $value, bool $multiple): string
231
    {
232
        if (!is_string($value) && !is_array($value)) {
×
233
            $value = '';
×
234
        }
235

236
        $options = [];
×
237
        foreach ($optArray as $key => $val) {
×
238
            $selected = (
×
239
                !$multiple && is_string($value) && !strcmp($value, (string) $key)
×
240
            ) || (
×
241
                $multiple && in_array($key, (array) $value, true)
×
242
            );
×
243
            $options[] = '
×
244
                <option value="' . $key . '" ' . ($selected ? ' selected="selected"' : '') . '>' . htmlspecialchars(
×
245
                (string) $val,
×
246
                ENT_QUOTES | ENT_HTML5
×
247
            ) . '</option>';
×
248
        }
249

250
        return '<select class="form-select" name="' . htmlspecialchars(
×
251
            $name . ($multiple ? '[]' : ''),
×
252
            ENT_QUOTES | ENT_HTML5
×
253
        ) . '"' . ($multiple ? ' multiple' : '') . '>' . implode('', $options) . '</select>';
×
254
    }
255

256
    private function getScheduledTime(string $time): int
257
    {
258
        $scheduledTime = match ($time) {
×
259
            'midnight' => mktime(0, 0, 0),
×
260
            '04:00' => mktime(0, 0, 0) + 4 * 3600,
×
261
            default => time(),
×
262
        };
×
263

264
        if (!$scheduledTime) {
×
265
            return time();
×
266
        }
267

268
        return $scheduledTime;
×
269
    }
270

271
    /**
272
     * @throws RouteNotFoundException
273
     */
274
    private function getActionUrl(): UriInterface
275
    {
276
        return GeneralUtility::makeInstance(UrlBuilder::class)->getBackendModuleUrl([], self::BACKEND_MODULE);
×
277
    }
278

279
    private function isNoConfigurationSelected(): bool
280
    {
281
        return empty($this->incomingConfigurationSelection)
×
282
            || (count($this->incomingConfigurationSelection) === 1 && empty($this->incomingConfigurationSelection[0]));
×
283
    }
284
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc