Skip to content

Commit 40ff42b

Browse files
authored
Make the RequestIntegration integration fetch the request from the request stack (#361)
1 parent c95a2bd commit 40ff42b

File tree

11 files changed

+223
-16
lines changed

11 files changed

+223
-16
lines changed

.github/workflows/tests.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ jobs:
5353
php-version: ${{ matrix.php }}
5454
coverage: xdebug
5555
- run: |
56-
sed -ri '/symfony\/(monolog-bundle|phpunit-bridge|messenger)/! s/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony_constraint }}'"/' composer.json;
56+
sed -ri '/symfony\/(monolog-bundle|phpunit-bridge|messenger|psr-http-message-bridge)/! s/"symfony\/(.+)": "(.+)"/"symfony\/\1": "'${{ matrix.symfony_constraint }}'"/' composer.json;
5757
if: matrix.symfony_constraint
5858
- run: composer remove --dev symfony/messenger --no-update
5959
if: matrix.symfony_constraint == '3.4.*' || matrix.composer_option == '--prefer-lowest'

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
- [BC BREAK] Refactorized the configuration tree and the definitions of some container services (#401)
1212
- Support the XML format for the bundle configuration (#401)
1313
- PHP 8 support (#399, thanks to @Yozhef)
14+
- Retrieve the request from the `RequestStack` when using the `RequestIntegration` integration (#361)
1415

1516
## 3.5.3 (2020-10-13)
1617

composer.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
"symfony/dependency-injection": "^3.4.43||^4.4.11||^5.0.11",
2929
"symfony/event-dispatcher": "^3.4.43||^4.4.11||^5.0.11",
3030
"symfony/http-kernel": "^3.4.43||^4.4.11||^5.0.11",
31+
"symfony/psr-http-message-bridge": "^2.0",
3132
"symfony/security-core": "^3.4.43||^4.4.11||^5.0.11"
3233
},
3334
"require-dev": {

src/DependencyInjection/SentryExtension.php

Lines changed: 53 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
use Sentry\Client;
1010
use Sentry\ClientBuilder;
1111
use Sentry\Integration\IgnoreErrorsIntegration;
12+
use Sentry\Integration\IntegrationInterface;
13+
use Sentry\Integration\RequestFetcherInterface;
14+
use Sentry\Integration\RequestIntegration;
1215
use Sentry\Monolog\Handler;
1316
use Sentry\Options;
1417
use Sentry\SentryBundle\EventListener\ErrorListener;
@@ -98,7 +101,7 @@ private function registerConfiguration(ContainerBuilder $container, array $confi
98101
}
99102

100103
if (isset($options['integrations'])) {
101-
$options['integrations'] = $this->configureIntegrationsOption($options['integrations'], $config['register_error_listener']);
104+
$options['integrations'] = $this->configureIntegrationsOption($options['integrations'], $config);
102105
}
103106

104107
$container
@@ -176,17 +179,30 @@ private function registerMonologHandlerConfiguration(ContainerBuilder $container
176179

177180
/**
178181
* @param string[] $integrations
182+
* @param array<string, mixed> $config
179183
*
180184
* @return array<Reference|Definition>
181185
*/
182-
private function configureIntegrationsOption(array $integrations, bool $registerErrorListener): array
186+
private function configureIntegrationsOption(array $integrations, array $config): array
183187
{
184-
$existsIgnoreErrorsIntegration = in_array(IgnoreErrorsIntegration::class, $integrations, true);
185188
$integrations = array_map(static function (string $value): Reference {
186189
return new Reference($value);
187190
}, $integrations);
188191

189-
if ($registerErrorListener && false === $existsIgnoreErrorsIntegration) {
192+
$integrations = $this->configureErrorListenerIntegration($integrations, $config['register_error_listener']);
193+
$integrations = $this->configureRequestIntegration($integrations, $config['options']['default_integrations'] ?? true);
194+
195+
return $integrations;
196+
}
197+
198+
/**
199+
* @param array<Reference|Definition> $integrations
200+
*
201+
* @return array<Reference|Definition>
202+
*/
203+
private function configureErrorListenerIntegration(array $integrations, bool $registerErrorListener): array
204+
{
205+
if ($registerErrorListener && ! $this->isIntegrationEnabled(IgnoreErrorsIntegration::class, $integrations)) {
190206
// Prepend this integration to the beginning of the array so that
191207
// we can save some performance by skipping the rest of the integrations
192208
// if the error must be ignored
@@ -195,4 +211,37 @@ private function configureIntegrationsOption(array $integrations, bool $register
195211

196212
return $integrations;
197213
}
214+
215+
/**
216+
* @param array<Reference|Definition> $integrations
217+
*
218+
* @return array<Reference|Definition>
219+
*/
220+
private function configureRequestIntegration(array $integrations, bool $useDefaultIntegrations): array
221+
{
222+
if ($useDefaultIntegrations && ! $this->isIntegrationEnabled(RequestIntegration::class, $integrations)) {
223+
$integrations[] = new Definition(RequestIntegration::class, [new Reference(RequestFetcherInterface::class)]);
224+
}
225+
226+
return $integrations;
227+
}
228+
229+
/**
230+
* @param class-string<IntegrationInterface> $integrationClass
231+
* @param array<Reference|Definition> $integrations
232+
*/
233+
private function isIntegrationEnabled(string $integrationClass, array $integrations): bool
234+
{
235+
foreach ($integrations as $integration) {
236+
if ($integration instanceof Reference && $integrationClass === (string) $integration) {
237+
return true;
238+
}
239+
240+
if ($integration instanceof Definition && $integrationClass === $integration->getClass()) {
241+
return true;
242+
}
243+
}
244+
245+
return false;
246+
}
198247
}

src/Integration/RequestFetcher.php

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\Integration;
6+
7+
use Psr\Http\Message\ServerRequestInterface;
8+
use Sentry\Integration\RequestFetcherInterface;
9+
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
10+
use Symfony\Component\HttpFoundation\RequestStack;
11+
12+
/**
13+
* This class fetches the server request from the request stack and converts it
14+
* into a PSR-7 request that is suitable to be used by the {@see \Sentry\Integration\RequestIntegration}
15+
* integration.
16+
*/
17+
final class RequestFetcher implements RequestFetcherInterface
18+
{
19+
/**
20+
* @var RequestStack The request stack
21+
*/
22+
private $requestStack;
23+
24+
/**
25+
* @var HttpMessageFactoryInterface The factory to convert Symfony requests to PSR-7 requests
26+
*/
27+
private $httpMessageFactory;
28+
29+
/**
30+
* Class constructor.
31+
*
32+
* @param RequestStack $requestStack The request stack
33+
* @param HttpMessageFactoryInterface $httpMessageFactory The factory to convert Symfony requests to PSR-7 requests
34+
*/
35+
public function __construct(RequestStack $requestStack, HttpMessageFactoryInterface $httpMessageFactory)
36+
{
37+
$this->requestStack = $requestStack;
38+
$this->httpMessageFactory = $httpMessageFactory;
39+
}
40+
41+
/**
42+
* {@inheritdoc}
43+
*/
44+
public function fetchRequest(): ?ServerRequestInterface
45+
{
46+
$request = $this->requestStack->getCurrentRequest();
47+
48+
if (null === $request) {
49+
return null;
50+
}
51+
52+
return $this->httpMessageFactory->createRequest($request);
53+
}
54+
}

src/Resources/config/services.xml

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,5 +66,33 @@
6666
<service id="Sentry\Monolog\Handler" class="Sentry\Monolog\Handler">
6767
<argument type="service" id="Sentry\State\HubInterface" />
6868
</service>
69+
70+
<service id="Sentry\Integration\RequestFetcherInterface" class="Sentry\SentryBundle\Integration\RequestFetcher">
71+
<argument type="service" id="Symfony\Component\HttpFoundation\RequestStack" />
72+
<argument type="service">
73+
<service class="Symfony\Bridge\PsrHttpMessage\Factory\PsrHttpFactory">
74+
<argument type="service">
75+
<service class="Psr\Http\Message\ServerRequestFactoryInterface">
76+
<factory class="Http\Discovery\Psr17FactoryDiscovery" method="findServerRequestFactory" />
77+
</service>
78+
</argument>
79+
<argument type="service">
80+
<service class="Psr\Http\Message\StreamFactoryInterface">
81+
<factory class="Http\Discovery\Psr17FactoryDiscovery" method="findStreamFactory" />
82+
</service>
83+
</argument>
84+
<argument type="service">
85+
<service class="Psr\Http\Message\UploadedFileFactoryInterface">
86+
<factory class="Http\Discovery\Psr17FactoryDiscovery" method="findUploadedFileFactory" />
87+
</service>
88+
</argument>
89+
<argument type="service">
90+
<service class="Psr\Http\Message\ResponseFactoryInterface">
91+
<factory class="Http\Discovery\Psr17FactoryDiscovery" method="findResponseFactory" />
92+
</service>
93+
</argument>
94+
</service>
95+
</argument>
96+
</service>
6997
</services>
7098
</container>

test/DependencyInjection/Fixtures/php/ignore_errors_integration_overridden.php

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
$container->loadFromExtension('sentry', [
99
'options' => [
1010
'integrations' => [
11-
'App\\Sentry\\Integration\\FooIntegration',
1211
'Sentry\\Integration\\IgnoreErrorsIntegration',
1312
],
1413
],

test/DependencyInjection/Fixtures/xml/ignore_errors_integration_overridden.xml

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

99
<sentry:config>
1010
<sentry:options>
11-
<sentry:integration>App\Sentry\Integration\FooIntegration</sentry:integration>
1211
<sentry:integration>Sentry\Integration\IgnoreErrorsIntegration</sentry:integration>
1312
</sentry:options>
1413
</sentry:config>
Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
sentry:
22
options:
33
integrations:
4-
- App\Sentry\Integration\FooIntegration
54
- Sentry\Integration\IgnoreErrorsIntegration

test/DependencyInjection/SentryExtensionTest.php

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -72,10 +72,8 @@ public function errorListenerDataProvider(): \Generator
7272
public function testErrorListenerIsRemovedWhenDisabled(): void
7373
{
7474
$container = $this->createContainerFromFixture('error_listener_disabled');
75-
$optionsDefinition = $container->getDefinition('sentry.client.options');
7675

7776
$this->assertFalse($container->hasDefinition(ErrorListener::class));
78-
$this->assertSame([], $optionsDefinition->getArgument(0)['integrations']);
7977
}
8078

8179
/**
@@ -369,13 +367,20 @@ public function testErrorTypesOptionIsParsedFromStringToIntegerValue(): void
369367
public function testIgnoreErrorsIntegrationIsNotAddedTwiceIfAlreadyConfigured(): void
370368
{
371369
$container = $this->createContainerFromFixture('ignore_errors_integration_overridden');
372-
$optionsDefinition = $container->getDefinition('sentry.client.options');
373-
$expectedIntegrations = [
374-
new Reference('App\\Sentry\\Integration\\FooIntegration'),
375-
new Reference(IgnoreErrorsIntegration::class),
376-
];
370+
$integrations = $container->getDefinition('sentry.client.options')->getArgument(0)['integrations'];
371+
$ignoreErrorsIntegrationsCount = 0;
372+
373+
foreach ($integrations as $integration) {
374+
if ($integration instanceof Reference && IgnoreErrorsIntegration::class === (string) $integration) {
375+
++$ignoreErrorsIntegrationsCount;
376+
}
377+
378+
if ($integration instanceof Definition && IgnoreErrorsIntegration::class === $integration->getClass()) {
379+
++$ignoreErrorsIntegrationsCount;
380+
}
381+
}
377382

378-
$this->assertEquals($expectedIntegrations, $optionsDefinition->getArgument(0)['integrations']);
383+
$this->assertSame(1, $ignoreErrorsIntegrationsCount);
379384
}
380385

381386
private function createContainerFromFixture(string $fixtureFile): ContainerBuilder
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace Sentry\SentryBundle\Test\Integration;
6+
7+
use GuzzleHttp\Psr7\ServerRequest;
8+
use PHPUnit\Framework\MockObject\MockObject;
9+
use PHPUnit\Framework\TestCase;
10+
use Psr\Http\Message\ServerRequestInterface;
11+
use Sentry\SentryBundle\Integration\RequestFetcher;
12+
use Symfony\Bridge\PsrHttpMessage\HttpMessageFactoryInterface;
13+
use Symfony\Component\HttpFoundation\Request;
14+
use Symfony\Component\HttpFoundation\RequestStack;
15+
16+
final class RequestFetcherTest extends TestCase
17+
{
18+
/**
19+
* @var RequestStack&MockObject
20+
*/
21+
private $requestStack;
22+
23+
/**
24+
* @var HttpMessageFactoryInterface&MockObject
25+
*/
26+
private $httpMessageFactory;
27+
28+
/**
29+
* @var RequestFetcher
30+
*/
31+
private $requestFetcher;
32+
33+
protected function setUp(): void
34+
{
35+
$this->requestStack = $this->createMock(RequestStack::class);
36+
$this->httpMessageFactory = $this->createMock(HttpMessageFactoryInterface::class);
37+
$this->requestFetcher = new RequestFetcher($this->requestStack, $this->httpMessageFactory);
38+
}
39+
40+
/**
41+
* @dataProvider fetchRequestDataProvider
42+
*/
43+
public function testFetchRequest(?Request $request, ?ServerRequestInterface $expectedRequest): void
44+
{
45+
$this->requestStack->expects($this->once())
46+
->method('getCurrentRequest')
47+
->willReturn($request);
48+
49+
$this->httpMessageFactory->expects(null !== $expectedRequest ? $this->once() : $this->never())
50+
->method('createRequest')
51+
->with($request)
52+
->willReturn($expectedRequest);
53+
54+
$this->assertSame($expectedRequest, $this->requestFetcher->fetchRequest());
55+
}
56+
57+
/**
58+
* @return \Generator<mixed>
59+
*/
60+
public function fetchRequestDataProvider(): \Generator
61+
{
62+
yield [
63+
null,
64+
null,
65+
];
66+
67+
yield [
68+
Request::create('http://www.example.com'),
69+
new ServerRequest('GET', 'http://www.example.com'),
70+
];
71+
}
72+
}

0 commit comments

Comments
 (0)