Skip to content

Commit cc57258

Browse files
Merge pull request #912 from eliashaeussler/task/user-agent
[TASK] Move access to `User-Agent` header to a `RequestOptions` class
2 parents 539f41b + 067eb37 commit cc57258

File tree

16 files changed

+241
-50
lines changed

16 files changed

+241
-50
lines changed

Classes/Command/ShowUserAgentCommand.php

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323

2424
namespace EliasHaeussler\Typo3Warming\Command;
2525

26-
use EliasHaeussler\Typo3Warming\Configuration;
26+
use EliasHaeussler\Typo3Warming\Http;
2727
use Symfony\Component\Console;
2828

2929
/**
@@ -34,10 +34,13 @@
3434
*/
3535
final class ShowUserAgentCommand extends Console\Command\Command
3636
{
37-
public function __construct(
38-
private readonly Configuration\Configuration $configuration,
39-
) {
37+
private readonly string $userAgent;
38+
39+
public function __construct(Http\Message\Request\RequestOptions $requestOptions)
40+
{
4041
parent::__construct();
42+
43+
$this->userAgent = $requestOptions->getUserAgent();
4144
}
4245

4346
protected function configure(): void
@@ -47,7 +50,7 @@ protected function configure(): void
4750

4851
protected function execute(Console\Input\InputInterface $input, Console\Output\OutputInterface $output): int
4952
{
50-
$output->write($this->configuration->getUserAgent());
53+
$output->write($this->userAgent);
5154

5255
return self::SUCCESS;
5356
}

Classes/Command/WarmupCommand.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ public function __construct(
5656
private readonly EventDispatcher\EventDispatcherInterface $eventDispatcher,
5757
private readonly Core\Package\PackageManager $packageManager,
5858
private readonly Http\Message\PageUriBuilder $pageUriBuilder,
59+
private readonly Http\Message\Request\RequestOptions $requestOptions,
5960
) {
6061
parent::__construct();
6162
}
@@ -173,7 +174,7 @@ protected function configure(): void
173174
├─ When the default crawler is used, each warmup request is executed with a special User-Agent header.
174175
│ This header is generated from the encryption key of the TYPO3 installation.
175176
│ It can be used, for example, to exclude warmup requests from your search statistics.
176-
└─ Current User-Agent: <info>{$v($this->configuration->getUserAgent())}</info>
177+
└─ Current User-Agent: <info>{$v($this->requestOptions->getUserAgent())}</info>
177178
HELP
178179
);
179180

Classes/Configuration/Configuration.php

Lines changed: 15 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -26,9 +26,9 @@
2626
use EliasHaeussler\CacheWarmup;
2727
use EliasHaeussler\Typo3Warming\Crawler;
2828
use EliasHaeussler\Typo3Warming\Extension;
29+
use EliasHaeussler\Typo3Warming\Http;
2930
use mteu\TypedExtConf;
3031
use TYPO3\CMS\Core;
31-
use TYPO3\CMS\Extbase;
3232

3333
/**
3434
* Configuration
@@ -40,7 +40,6 @@
4040
final class Configuration
4141
{
4242
private ?CacheWarmup\Crawler\CrawlerFactory $crawlerFactory = null;
43-
private readonly string $userAgent;
4443

4544
/**
4645
* @param class-string<CacheWarmup\Crawler\Crawler> $crawlerClass
@@ -78,9 +77,7 @@ public function __construct(
7877
public readonly array $supportedDoktypes = [Core\Domain\Repository\PageRepository::DOKTYPE_DEFAULT],
7978
#[TypedExtConf\Attribute\ExtConfProperty(path: 'enableToolbar')]
8079
public readonly bool $enabledInToolbar = true,
81-
) {
82-
$this->userAgent = $this->generateUserAgent();
83-
}
80+
) {}
8481

8582
/**
8683
* @param array{} $arguments
@@ -138,32 +135,26 @@ public function getVerboseCrawler(): CacheWarmup\Crawler\VerboseCrawler
138135
return $this->getCrawlerFactory()->get($this->verboseCrawlerClass, $this->verboseCrawlerOptions);
139136
}
140137

138+
/**
139+
* @deprecated Use {@see RequestOptions::getUserAgent()} instead. Will be removed in v5.0.
140+
*/
141141
public function getUserAgent(): string
142142
{
143-
return $this->userAgent;
144-
}
145-
146-
private function generateUserAgent(): string
147-
{
148-
$string = 'TYPO3/tx_warming_crawler';
149-
150-
if (class_exists(Core\Crypto\HashService::class)) {
151-
return Core\Utility\GeneralUtility::makeInstance(Core\Crypto\HashService::class)->appendHmac(
152-
$string,
153-
self::class,
154-
);
155-
}
156-
157-
// @todo Remove once support for TYPO3 v12 is dropped
158-
/* @phpstan-ignore classConstant.deprecatedClass, method.deprecatedClass */
159-
return Core\Utility\GeneralUtility::makeInstance(Extbase\Security\Cryptography\HashService::class)->appendHmac(
160-
$string,
143+
trigger_error(
144+
\sprintf(
145+
'Method "%s()" is deprecated and will be removed in v5.0. ' .
146+
'Access User-Agent header via "%s::getUserAgent()" method instead.',
147+
__METHOD__,
148+
Http\Message\Request\RequestOptions::class,
149+
),
150+
E_USER_DEPRECATED,
161151
);
152+
153+
return (new Http\Message\Request\RequestOptions())->getUserAgent();
162154
}
163155

164156
private function getCrawlerFactory(): CacheWarmup\Crawler\CrawlerFactory
165157
{
166-
// Cannot be instantiated with DI, would lead to circular dependencies
167158
return $this->crawlerFactory ??= Core\Utility\GeneralUtility::makeInstance(
168159
CacheWarmup\Crawler\CrawlerFactory::class,
169160
);

Classes/Controller/FetchSitesController.php

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ public function __construct(
4848
private Configuration\Configuration $configuration,
4949
private CacheWarmup\Crawler\Strategy\CrawlingStrategyFactory $crawlingStrategyFactory,
5050
private Core\Imaging\IconFactory $iconFactory,
51+
private Http\Message\Request\RequestOptions $requestOptions,
5152
private Http\Message\ResponseFactory $responseFactory,
5253
private Domain\Repository\SiteRepository $siteRepository,
5354
private Domain\Repository\SiteLanguageRepository $siteLanguageRepository,
@@ -92,7 +93,7 @@ public function __invoke(Message\ServerRequestInterface $request): Message\Respo
9293

9394
return $this->responseFactory->htmlTemplate('Modal/SitesModal', [
9495
'siteGroups' => $siteGroups,
95-
'userAgent' => $this->configuration->getUserAgent(),
96+
'userAgent' => $this->requestOptions->getUserAgent(),
9697
'configuration' => [
9798
'limit' => $this->configuration->limit,
9899
'strategy' => $crawlingStrategy !== null ? $crawlingStrategy::getName() : null,

Classes/Crawler/ConcurrentUserAgentCrawler.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525

2626
use EliasHaeussler\CacheWarmup;
2727
use EliasHaeussler\SSE;
28-
use EliasHaeussler\Typo3Warming\Configuration;
2928
use EliasHaeussler\Typo3Warming\Http;
3029
use GuzzleHttp\Client;
3130
use GuzzleHttp\ClientInterface;
@@ -57,8 +56,8 @@ final class ConcurrentUserAgentCrawler extends CacheWarmup\Crawler\AbstractConfi
5756
}
5857
use LoggingCrawlerTrait;
5958

60-
private readonly Configuration\Configuration $configuration;
6159
private readonly Http\Client\Handler\HandlerStackBuilder $handlerStackBuilder;
60+
private readonly Http\Message\Request\RequestOptions $requestOptions;
6261
private readonly Http\Client\Handler\SubRequestHandler $subRequestHandler;
6362
private ?SSE\Stream\EventStream $stream = null;
6463

@@ -68,8 +67,8 @@ public function __construct(
6867
private readonly ClientInterface $client = new Client(),
6968
private readonly ?EventDispatcher\EventDispatcherInterface $eventDispatcher = null,
7069
) {
71-
$this->configuration = Core\Utility\GeneralUtility::makeInstance(Configuration\Configuration::class);
7270
$this->handlerStackBuilder = new Http\Client\Handler\HandlerStackBuilder();
71+
$this->requestOptions = Core\Utility\GeneralUtility::makeInstance(Http\Message\Request\RequestOptions::class);
7372
$this->subRequestHandler = Core\Utility\GeneralUtility::makeInstance(Http\Client\Handler\SubRequestHandler::class);
7473
$this->logger = $logger;
7574

@@ -132,7 +131,7 @@ protected function configureOptions(OptionsResolver\OptionsResolver $optionsReso
132131
protected function createRequestFactory(): CacheWarmup\Http\Message\RequestFactory
133132
{
134133
$headers = $this->options['request_headers'];
135-
$headers['User-Agent'] = $this->configuration->getUserAgent();
134+
$headers['User-Agent'] = $this->requestOptions->getUserAgent();
136135

137136
return $this->createBaseRequestFactory()->withHeaders($headers);
138137
}

Classes/Crawler/OutputtingUserAgentCrawler.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
namespace EliasHaeussler\Typo3Warming\Crawler;
2525

2626
use EliasHaeussler\CacheWarmup;
27-
use EliasHaeussler\Typo3Warming\Configuration;
2827
use EliasHaeussler\Typo3Warming\Http;
2928
use GuzzleHttp\Client;
3029
use GuzzleHttp\ClientInterface;
@@ -57,8 +56,8 @@ final class OutputtingUserAgentCrawler extends CacheWarmup\Crawler\AbstractConfi
5756
}
5857
use LoggingCrawlerTrait;
5958

60-
private readonly Configuration\Configuration $configuration;
6159
private Http\Client\Handler\HandlerStackBuilder $handlerStackBuilder;
60+
private readonly Http\Message\Request\RequestOptions $requestOptions;
6261
private readonly Http\Client\Handler\SubRequestHandler $subRequestHandler;
6362
private Console\Output\OutputInterface $output;
6463

@@ -68,8 +67,8 @@ public function __construct(
6867
private readonly ClientInterface $client = new Client(),
6968
private readonly ?EventDispatcher\EventDispatcherInterface $eventDispatcher = null,
7069
) {
71-
$this->configuration = Core\Utility\GeneralUtility::makeInstance(Configuration\Configuration::class);
7270
$this->handlerStackBuilder = new Http\Client\Handler\HandlerStackBuilder();
71+
$this->requestOptions = Core\Utility\GeneralUtility::makeInstance(Http\Message\Request\RequestOptions::class);
7372
$this->subRequestHandler = Core\Utility\GeneralUtility::makeInstance(Http\Client\Handler\SubRequestHandler::class);
7473
$this->logger = $logger;
7574

@@ -133,7 +132,7 @@ protected function configureOptions(OptionsResolver\OptionsResolver $optionsReso
133132
protected function createRequestFactory(): CacheWarmup\Http\Message\RequestFactory
134133
{
135134
$headers = $this->options['request_headers'];
136-
$headers['User-Agent'] = $this->configuration->getUserAgent();
135+
$headers['User-Agent'] = $this->requestOptions->getUserAgent();
137136

138137
return $this->createBaseRequestFactory()->withHeaders($headers);
139138
}
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
/*
6+
* This file is part of the TYPO3 CMS extension "warming".
7+
*
8+
* Copyright (C) 2021-2025 Elias Häußler <elias@haeussler.dev>
9+
*
10+
* This program is free software: you can redistribute it and/or modify
11+
* it under the terms of the GNU General Public License as published by
12+
* the Free Software Foundation, either version 2 of the License, or
13+
* (at your option) any later version.
14+
*
15+
* This program is distributed in the hope that it will be useful,
16+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
* GNU General Public License for more details.
19+
*
20+
* You should have received a copy of the GNU General Public License
21+
* along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
24+
namespace EliasHaeussler\Typo3Warming\Http\Message\Request;
25+
26+
use EliasHaeussler\Typo3Warming\Configuration;
27+
use Symfony\Component\DependencyInjection;
28+
use TYPO3\CMS\Core;
29+
use TYPO3\CMS\Extbase;
30+
31+
/**
32+
* RequestOptions
33+
*
34+
* @author Elias Häußler <elias@haeussler.dev>
35+
* @license GPL-2.0-or-later
36+
*/
37+
#[DependencyInjection\Attribute\Autoconfigure(public: true)]
38+
final readonly class RequestOptions
39+
{
40+
public function getUserAgent(): string
41+
{
42+
$string = 'TYPO3/tx_warming_crawler';
43+
44+
if (class_exists(Core\Crypto\HashService::class)) {
45+
return Core\Utility\GeneralUtility::makeInstance(Core\Crypto\HashService::class)->appendHmac(
46+
$string,
47+
// @todo Change to self::class in v5.0
48+
Configuration\Configuration::class,
49+
);
50+
}
51+
52+
// @todo Remove once support for TYPO3 v12 is dropped
53+
/* @phpstan-ignore classConstant.deprecatedClass, method.deprecatedClass */
54+
return Core\Utility\GeneralUtility::makeInstance(Extbase\Security\Cryptography\HashService::class)->appendHmac(
55+
$string,
56+
);
57+
}
58+
}

Documentation/DeveloperCorner/ConfigurationAPI.rst

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Configuration API
88

99
In order to access the :ref:`extension configuration <extension-configuration>`,
1010
a slim PHP API exists. Each configuration option is accessible by
11-
an appropriate class method.
11+
an appropriate class property.
1212

1313
.. versionchanged:: 4.2.0
1414

@@ -89,6 +89,11 @@ an appropriate class method.
8989
9090
Get the calculated user-agent.
9191

92+
.. deprecated:: 4.2.0
93+
94+
Call :php:`\EliasHaeussler\Typo3Warming\Http\Message\Request\RequestOptions::getUserAgent`
95+
instead. See :ref:`migration guide <version-4.2.0>` for more information.
96+
9297
:returntype: :php:`string`
9398

9499
.. seealso::

Documentation/Migration/Index.rst

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,16 @@ Use of properties in :ref:`Configuration API <configuration-api>`
2929
- Calling the legacy class methods is deprecated and won't be possible anymore with version
3030
5.0 of the extension.
3131

32+
Deprecation of :php:`getUserAgent()` method in :ref:`Configuration API <configuration-api>`
33+
-------------------------------------------------------------------------------------------
34+
35+
- Access to the generated `User-Agent` header is moved from the :ref:`Configuration API <configuration-api>`
36+
to a dedicated :php:`\EliasHaeussler\Typo3Warming\Http\Message\Request\RequestOptions` class.
37+
- Migrate calls from :php:`\EliasHaeussler\Typo3Warming\Configuration\Configuration::getUserAgent`
38+
to :php:`\EliasHaeussler\Typo3Warming\Http\Message\Request\RequestOptions::getUserAgent`.
39+
- Calling the legacy method is deprecated and won't be possible anymore with version 5.0
40+
of the extension.
41+
3242
.. _version-4.0.0:
3343

3444
Version 4.0.0

Tests/CGL/rector.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,13 +76,13 @@
7676
])
7777
// @todo Remove once support for TYPO3 v12 is dropped
7878
->skip(MigrateExtbaseHashServiceToUseCoreHashServiceRector::class, [
79-
$rootPath . '/Classes/Configuration/Configuration.php',
79+
$rootPath . '/Classes/Http/Message/Request/RequestOptions.php',
8080
$rootPath . '/Classes/Http/Message/UrlMetadataFactory.php',
8181
$rootPath . '/Tests/Functional/Http/Message/UrlMetadataFactoryTest.php',
8282
])
8383
// @todo Remove once support for TYPO3 v12 is dropped
8484
->skip(RenameClassRector::class, [
85-
$rootPath . '/Classes/Configuration/Configuration.php',
85+
$rootPath . '/Classes/Http/Message/Request/RequestOptions.php',
8686
$rootPath . '/Classes/Http/Message/UrlMetadataFactory.php',
8787
$rootPath . '/Tests/Functional/Http/Message/UrlMetadataFactoryTest.php',
8888
])

0 commit comments

Comments
 (0)