Skip to content

Commit 4d952a7

Browse files
authored
Merge pull request #193 from getsentry/add-options-as-services
Add before_send option
2 parents 5ce8775 + fa6c334 commit 4d952a7

File tree

5 files changed

+134
-3
lines changed

5 files changed

+134
-3
lines changed

composer.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@
3535
"php-http/mock-client": "^1.0",
3636
"phpstan/phpstan": "^0.11",
3737
"phpstan/phpstan-phpunit": "^0.11",
38-
"phpunit/phpunit": "^7",
38+
"phpunit/phpunit": "^7.5",
3939
"scrutinizer/ocular": "^1.4",
4040
"symfony/expression-language": "^3.0||^4.0"
4141
},

src/DependencyInjection/Configuration.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,12 @@ public function getConfigTreeBuilder()
4747
->children()
4848
->booleanNode('attach_stacktrace')->end()
4949
// TODO -- before_breadcrumb
50-
// TODO -- before_send
50+
->variableNode('before_send')
51+
->validate()
52+
->ifTrue($this->isNotAValidCallback())
53+
->thenInvalid('Expecting callable or service reference, got %s')
54+
->end()
55+
->end()
5156
->booleanNode('default_integrations')->end()
5257
->integerNode('context_lines')
5358
->min(0)
@@ -137,4 +142,19 @@ private function getProjectRoot(): string
137142

138143
return '%kernel.root_dir%/..';
139144
}
145+
146+
private function isNotAValidCallback(): \Closure
147+
{
148+
return function ($value): bool {
149+
if (is_callable($value)) {
150+
return false;
151+
}
152+
153+
if (is_string($value) && 0 === strpos($value, '@')) {
154+
return false;
155+
}
156+
157+
return true;
158+
};
159+
}
140160
}

src/DependencyInjection/SentryExtension.php

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Symfony\Component\Config\FileLocator;
1111
use Symfony\Component\DependencyInjection\ContainerBuilder;
1212
use Symfony\Component\DependencyInjection\Loader;
13+
use Symfony\Component\DependencyInjection\Reference;
1314
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
1415

1516
/**
@@ -83,5 +84,16 @@ private function passConfigurationToOptions(ContainerBuilder $container, array $
8384
$parsedValue = (new ErrorTypesParser($processedOptions['error_types']))->parse();
8485
$options->addMethodCall('setErrorTypes', [$parsedValue]);
8586
}
87+
88+
if (\array_key_exists('before_send', $processedOptions)) {
89+
$optionValue = $processedOptions['before_send'];
90+
if (is_string($optionValue) && 0 === strpos($optionValue, '@')) {
91+
$beforeSend = new Reference(substr($optionValue, 1));
92+
} else {
93+
$beforeSend = $optionValue;
94+
}
95+
96+
$options->addMethodCall('setBeforeSendCallback', [$beforeSend]);
97+
}
8698
}
8799
}

test/DependencyInjection/ConfigurationTest.php

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111

1212
class ConfigurationTest extends TestCase
1313
{
14-
public const SUPPORTED_SENTRY_OPTIONS_COUNT = 19;
14+
public const SUPPORTED_SENTRY_OPTIONS_COUNT = 20;
1515

1616
public function testDataProviderIsMappingTheRightNumberOfOptions(): void
1717
{
@@ -84,6 +84,7 @@ public function optionValuesProvider(): array
8484
{
8585
return [
8686
['attach_stacktrace', true],
87+
['before_send', 'count'],
8788
['context_lines', 4],
8889
['context_lines', 99],
8990
['default_integrations', true],
@@ -125,6 +126,10 @@ public function invalidValuesProvider(): array
125126
{
126127
return [
127128
['attach_stacktrace', 'string'],
129+
['before_send', 'this is not a callable'],
130+
['before_send', [$this, 'is not a callable']],
131+
['before_send', false],
132+
['before_send', -1],
128133
['context_lines', -1],
129134
['context_lines', 99999],
130135
['context_lines', 'string'],

test/DependencyInjection/SentryExtensionTest.php

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,13 +3,15 @@
33
namespace Sentry\SentryBundle\Test\DependencyInjection;
44

55
use PHPUnit\Framework\TestCase;
6+
use Sentry\Event;
67
use Sentry\Options;
78
use Sentry\SentryBundle\DependencyInjection\SentryExtension;
89
use Sentry\SentryBundle\EventListener\ConsoleListener;
910
use Sentry\SentryBundle\EventListener\RequestListener;
1011
use Symfony\Component\DependencyInjection\Alias;
1112
use Symfony\Component\DependencyInjection\Container;
1213
use Symfony\Component\DependencyInjection\ContainerBuilder;
14+
use Symfony\Component\DependencyInjection\Definition;
1315
use Symfony\Component\EventDispatcher\EventDispatcherInterface;
1416
use Symfony\Component\HttpFoundation\RequestStack;
1517
use Symfony\Component\HttpKernel\Kernel;
@@ -87,6 +89,7 @@ public function optionsValueProvider(): array
8789
{
8890
return [
8991
['attach_stacktrace', true, 'shouldAttachStacktrace'],
92+
['before_send', __NAMESPACE__ . '\mockBeforeSend', 'getBeforeSendCallback'],
9093
['context_lines', 1],
9194
['default_integrations', false, 'hasDefaultIntegrations'],
9295
['enable_compression', false, 'isCompressionEnabled'],
@@ -146,6 +149,75 @@ public function emptyDsnValueProvider(): array
146149
];
147150
}
148151

152+
public function testBeforeSendUsingServiceDefinition(): void
153+
{
154+
$container = $this->getContainer([
155+
'options' => [
156+
'before_send' => '@before_send',
157+
],
158+
]);
159+
160+
$beforeSendCallback = $this->getOptionsFrom($container)->getBeforeSendCallback();
161+
$this->assertIsCallable($beforeSendCallback);
162+
$defaultOptions = $this->getOptionsFrom($this->getContainer());
163+
$this->assertNotEquals(
164+
$defaultOptions->getBeforeSendCallback(),
165+
$beforeSendCallback,
166+
'before_send closure has not been replaced, is the default one'
167+
);
168+
$this->assertEquals(
169+
CallbackMock::createBeforeSendCallback(),
170+
$beforeSendCallback
171+
);
172+
}
173+
174+
/**
175+
* @dataProvider beforeSendDataProvider
176+
*/
177+
public function testBeforeSendUsingScalarCallable($scalarCallable): void
178+
{
179+
$container = $this->getContainer([
180+
'options' => [
181+
'before_send' => $scalarCallable,
182+
],
183+
]);
184+
185+
$beforeSendCallback = $this->getOptionsFrom($container)->getBeforeSendCallback();
186+
$this->assertIsCallable($beforeSendCallback);
187+
$defaultOptions = $this->getOptionsFrom($this->getContainer());
188+
$this->assertNotEquals(
189+
$defaultOptions->getBeforeSendCallback(),
190+
$beforeSendCallback,
191+
'before_send closure has not been replaced, is the default one'
192+
);
193+
$this->assertEquals(
194+
$scalarCallable,
195+
$beforeSendCallback
196+
);
197+
}
198+
199+
public function beforeSendDataProvider(): array
200+
{
201+
return [
202+
[[CallbackMock::class, 'beforeSend']],
203+
[CallbackMock::class . '::beforeSend'],
204+
[__NAMESPACE__ . '\mockBeforeSend'],
205+
];
206+
}
207+
208+
public function testBeforeSendWithInvalidServiceReference(): void
209+
{
210+
$container = $this->getContainer([
211+
'options' => [
212+
'before_send' => '@event_dispatcher',
213+
],
214+
]);
215+
216+
$this->expectException(\TypeError::class);
217+
218+
$this->getOptionsFrom($container)->getBeforeSendCallback();
219+
}
220+
149221
private function getContainer(array $configuration = []): Container
150222
{
151223
$containerBuilder = new ContainerBuilder();
@@ -168,6 +240,10 @@ private function getContainer(array $configuration = []): Container
168240
$containerBuilder->setAlias(self::REQUEST_LISTENER_TEST_PUBLIC_ALIAS, new Alias(RequestListener::class, true));
169241
$containerBuilder->setAlias(self::CONSOLE_LISTENER_TEST_PUBLIC_ALIAS, new Alias(ConsoleListener::class, true));
170242

243+
$beforeSend = new Definition('callable');
244+
$beforeSend->setFactory([CallbackMock::class, 'createBeforeSendCallback']);
245+
$containerBuilder->setDefinition('before_send', $beforeSend);
246+
171247
$extension = new SentryExtension();
172248
$extension->load(['sentry' => $configuration], $containerBuilder);
173249

@@ -186,3 +262,21 @@ private function getOptionsFrom(Container $container): Options
186262
return $options;
187263
}
188264
}
265+
266+
function mockBeforeSend(Event $event): ?Event
267+
{
268+
return null;
269+
}
270+
271+
class CallbackMock
272+
{
273+
public static function beforeSend(Event $event): ?Event
274+
{
275+
return null;
276+
}
277+
278+
public static function createBeforeSendCallback(): callable
279+
{
280+
return [new self(), 'beforeSend'];
281+
}
282+
}

0 commit comments

Comments
 (0)