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

tomasnorre / crawler / 3721152729

pending completion
3721152729

Pull #988

github

GitHub
Merge 64c242322 into 4735d49b5
Pull Request #988: [WIP][FEATURE] Setup new Backend Module

434 of 434 new or added lines in 12 files covered. (100.0%)

1595 of 2533 relevant lines covered (62.97%)

3.21 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\UrlBuilder;
23
use AOE\Crawler\Controller\CrawlerController;
24
use AOE\Crawler\Domain\Model\Reason;
25
use AOE\Crawler\Event\InvokeQueueChangeEvent;
26
use AOE\Crawler\Utility\MessageUtility;
27
use Psr\Http\Message\ResponseInterface;
28
use Psr\Http\Message\ServerRequestInterface;
29
use Symfony\Contracts\Service\Attribute\Required;
30
use TYPO3\CMS\Backend\Routing\Exception\RouteNotFoundException;
31
use TYPO3\CMS\Backend\Template\ModuleTemplate;
32
use TYPO3\CMS\Core\EventDispatcher\EventDispatcher;
33
use TYPO3\CMS\Core\Http\Uri;
34
use TYPO3\CMS\Core\Utility\GeneralUtility;
35

36
/**
37
 * @internal since v12.0.0
38
 */
39
final class BackendModuleStartCrawlingController extends AbstractBackendModuleController implements BackendModuleControllerInterface
40
{
41
    private const BACKEND_MODULE = 'web_site_crawler_start';
42
    private int $reqMinute = 1000;
43
    private EventDispatcher $eventDispatcher;
44

45
    /**
46
     * @var array holds the selection of configuration from the configuration selector box
47
     */
48
    private $incomingConfigurationSelection = [];
49

50
    public function __construct(
51
        private CrawlerController $crawlerController
52
    ) {
53
    }
×
54

55
    #[Required]
56
    public function setEventDispatcher(): void
57
    {
58
        $this->eventDispatcher = GeneralUtility::makeInstance(EventDispatcher::class);
×
59
    }
60

61
    public function handleRequest(ServerRequestInterface $request): ResponseInterface
62
    {
63
        $this->makeCrawlerProcessableChecks($this->extensionSettings);
×
64
        $this->pageUid = (int) ($request->getQueryParams()['id'] ?? -1);
×
65
        $this->moduleTemplate = $this->setupView($request, $this->pageUid);
×
66
        $this->moduleTemplate->makeDocHeaderModuleMenu(['id' => $request->getQueryParams()['id'] ?? -1]);
×
67
        $this->assignValues();
×
68

69
        return $this->moduleTemplate->renderResponse('Backend/ShowCrawlerInformation');
×
70
    }
71

72
    private function assignValues(): ModuleTemplate
73
    {
74
        $backendUriBuilder = GeneralUtility::makeInstance(\TYPO3\CMS\Backend\Routing\UriBuilder::class);
×
75
        $logUrl = $backendUriBuilder->buildUriFromRoute('web_site_crawler_log', ['id' => $this->pageUid]);
×
76

77
        $crawlingDepth = GeneralUtility::_GP('crawlingDepth') ?? '0';
×
78
        $crawlParameter = GeneralUtility::_GP('_crawl');
×
79
        $downloadParameter = GeneralUtility::_GP('_download');
×
80
        $scheduledTime = $this->getScheduledTime((string) GeneralUtility::_GP('tstamp'));
×
81
        $submitCrawlUrls = isset($crawlParameter);
×
82
        $downloadCrawlUrls = isset($downloadParameter);
×
83

84
        $this->incomingConfigurationSelection = GeneralUtility::_GP('configurationSelection');
×
85
        $this->incomingConfigurationSelection = is_array(
×
86
            $this->incomingConfigurationSelection
×
87
        ) ? $this->incomingConfigurationSelection : [];
×
88

89
        //$this->crawlerController = $this->getCrawlerController();
90
        $this->crawlerController->setID = GeneralUtility::md5int(microtime());
×
91

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

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

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

131
            // Printing the content of the CSV lines:
132
            echo implode(chr(13) . chr(10), $downloadUrls);
×
133
            exit;
×
134
        }
135

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

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

181
        // Configurations
182
        $availableConfigurations = $this->crawlerController->getConfigurationsForBranch(
×
183
            $pageId,
×
184
            (int) $crawlingDepth,
×
185
        );
×
186
        $selectors['configurations'] = $this->selectorBox(
×
187
            empty($availableConfigurations) ? [] : array_combine($availableConfigurations, $availableConfigurations),
×
188
            'configurationSelection',
×
189
            $this->incomingConfigurationSelection,
×
190
            true
×
191
        );
×
192

193
        // Scheduled time:
194
        $selectors['scheduled'] = $this->selectorBox(
×
195
            [
×
196
                'now' => $this->getLanguageService()->sL(
×
197
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.now'
×
198
                ),
×
199
                'midnight' => $this->getLanguageService()->sL(
×
200
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.midnight'
×
201
                ),
×
202
                '04:00' => $this->getLanguageService()->sL(
×
203
                    'LLL:EXT:crawler/Resources/Private/Language/locallang.xlf:labels.time.4am'
×
204
                ),
×
205
            ],
×
206
            'tstamp',
×
207
            GeneralUtility::_POST('tstamp'),
×
208
            false
×
209
        );
×
210

211
        return $selectors;
×
212
    }
213

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

230
        $options = [];
×
231
        foreach ($optArray as $key => $val) {
×
232
            $selected = (!$multiple && !strcmp($value, (string) $key)) || ($multiple && in_array(
×
233
                $key,
×
234
                (array) $value,
×
235
                true
×
236
            ));
×
237
            $options[] = '
×
238
                <option value="' . $key . '" ' . ($selected ? ' selected="selected"' : '') . '>' . htmlspecialchars(
×
239
                $val,
×
240
                ENT_QUOTES | ENT_HTML5
×
241
            ) . '</option>';
×
242
        }
243

244
        return '<select class="form-control" name="' . htmlspecialchars(
×
245
            $name . ($multiple ? '[]' : ''),
×
246
            ENT_QUOTES | ENT_HTML5
×
247
        ) . '"' . ($multiple ? ' multiple' : '') . '>' . implode('', $options) . '</select>';
×
248
    }
249

250
    private function getScheduledTime(string $time): float|int
251
    {
252
        $scheduledTime = match ($time) {
×
253
            'midnight' => mktime(0, 0, 0),
×
254
            '04:00' => mktime(0, 0, 0) + 4 * 3600,
×
255
            default => time(),
×
256
        };
×
257

258
        if (!$scheduledTime) {
×
259
            return time();
×
260
        }
261

262
        return $scheduledTime;
×
263
    }
264

265
    /**
266
     * @throws RouteNotFoundException
267
     */
268
    private function getActionUrl(): Uri
269
    {
270
        return GeneralUtility::makeInstance(UrlBuilder::class)->getBackendModuleUrl([], self::BACKEND_MODULE);
×
271
    }
272
}
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

© 2025 Coveralls, Inc