Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add class_serializers option #245

Merged
merged 9 commits into from Sep 23, 2019
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Expand Up @@ -7,6 +7,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
- Add forward compatibility with Symfony 5 (#235, thanks to @garak)
- Fix compatibility with sentry/sentry 2.2+ (#244)
- Add support for `class_serializers` option (#245)

## 3.1.0 - 2019-07-02
- Add support for Symfony 2.8 (#233, thanks to @nocive)
Expand Down
22 changes: 19 additions & 3 deletions src/DependencyInjection/Configuration.php
Expand Up @@ -57,6 +57,11 @@ public function getConfigTreeBuilder(): TreeBuilder
if (PrettyVersions::getVersion('sentry/sentry')->getPrettyVersion() !== '2.0.0') {
$optionsChildNodes->booleanNode('capture_silenced_errors');
}
if ($this->classSerializersAreSupported()) {
$optionsChildNodes->arrayNode('class_serializers')
->defaultValue([])
->prototype('scalar');
}
$optionsChildNodes->integerNode('context_lines')
->min(0)
->max(99);
Expand All @@ -80,13 +85,13 @@ public function getConfigTreeBuilder(): TreeBuilder
->prototype('scalar')
->validate()
->ifTrue(function ($value): bool {
if (! is_string($value)) {
if (! is_string($value) && '' != $value) {
return true;
}

return '@' !== substr($value, 0, 1);
return '@' !== $value[0];
})
->thenInvalid('Expecting service reference, got %s');
->thenInvalid('Expecting service reference, got "%s"');
$optionsChildNodes->scalarNode('logger');
$optionsChildNodes->integerNode('max_breadcrumbs')
->min(1);
Expand Down Expand Up @@ -163,4 +168,15 @@ private function isNotAValidCallback(): \Closure
return true;
};
}

private function classSerializersAreSupported(): bool
{
try {
new Options(['class_serializers' => []]);

return true;
Jean85 marked this conversation as resolved.
Show resolved Hide resolved
} catch (\Throwable $throwable) {
return false;
Jean85 marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
31 changes: 17 additions & 14 deletions src/DependencyInjection/SentryExtension.php
Expand Up @@ -14,7 +14,6 @@
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Console\ConsoleEvents;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Component\DependencyInjection\Loader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\DependencyInjection\Extension;
Expand Down Expand Up @@ -97,11 +96,22 @@ private function passConfigurationToOptions(ContainerBuilder $container, array $
}

if (\array_key_exists('before_send', $processedOptions)) {
$this->mapCallableValue($options, 'setBeforeSendCallback', $processedOptions['before_send']);
$beforeSendCallable = $this->valueToCallable($processedOptions['before_send']);
$options->addMethodCall('setBeforeSendCallback', [$beforeSendCallable]);
}

if (\array_key_exists('before_breadcrumb', $processedOptions)) {
$this->mapCallableValue($options, 'setBeforeBreadcrumbCallback', $processedOptions['before_breadcrumb']);
$beforeBreadcrumbCallable = $this->valueToCallable($processedOptions['before_breadcrumb']);
$options->addMethodCall('setBeforeBreadcrumbCallback', [$beforeBreadcrumbCallable]);
}

if (\array_key_exists('class_serializers', $processedOptions)) {
$classSerializers = [];
foreach ($processedOptions['class_serializers'] as $class => $serializer) {
$classSerializers[$class] = $this->valueToCallable($serializer);
}

$options->addMethodCall('setClassSerializers', [$classSerializers]);
}

if (\array_key_exists('integrations', $processedOptions)) {
Expand All @@ -114,20 +124,13 @@ private function passConfigurationToOptions(ContainerBuilder $container, array $
}
}

/**
* @param Definition $options
* @param string $method
* @param callable|string $optionValue
*/
private function mapCallableValue(Definition $options, string $method, $optionValue): void
private function valueToCallable($value)
{
if (is_string($optionValue) && 0 === strpos($optionValue, '@')) {
$beforeSend = new Reference(substr($optionValue, 1));
} else {
$beforeSend = $optionValue;
if (is_string($value) && 0 === strpos($value, '@')) {
return new Reference(substr($value, 1));
}

$options->addMethodCall($method, [$beforeSend]);
return $value;
}

/**
Expand Down
30 changes: 30 additions & 0 deletions test/BaseTestCase.php
@@ -0,0 +1,30 @@
<?php

namespace Sentry\SentryBundle\Test;

use PHPUnit\Framework\TestCase;
use Sentry\Options;
use Sentry\SentryBundle\Test\DependencyInjection\ConfigurationTest;

abstract class BaseTestCase extends TestCase
{
protected function classSerializersAreSupported(): bool
{
try {
new Options(['class_serializers' => []]);

return true;
} catch (\Throwable $throwable) {
return false;
}
}

protected function getSupportedOptionsCount(): int
{
if ($this->classSerializersAreSupported()) {
return ConfigurationTest::SUPPORTED_SENTRY_OPTIONS_COUNT + 1;
}

return ConfigurationTest::SUPPORTED_SENTRY_OPTIONS_COUNT;
}
}
20 changes: 16 additions & 4 deletions test/DependencyInjection/ConfigurationTest.php
Expand Up @@ -3,14 +3,14 @@
namespace Sentry\SentryBundle\Test\DependencyInjection;

use Jean85\PrettyVersions;
use PHPUnit\Framework\TestCase;
use Sentry\Options;
use Sentry\SentryBundle\DependencyInjection\Configuration;
use Sentry\SentryBundle\Test\BaseTestCase;
use Symfony\Component\Config\Definition\Exception\InvalidConfigurationException;
use Symfony\Component\Config\Definition\Processor;
use Symfony\Component\HttpKernel\Kernel;

class ConfigurationTest extends TestCase
class ConfigurationTest extends BaseTestCase
{
public const SUPPORTED_SENTRY_OPTIONS_COUNT = 23;

Expand All @@ -19,7 +19,7 @@ public function testDataProviderIsMappingTheRightNumberOfOptions(): void
$providerData = $this->optionValuesProvider();
$supportedOptions = \array_unique(\array_column($providerData, 0));

$expectedCount = self::SUPPORTED_SENTRY_OPTIONS_COUNT;
$expectedCount = $this->getSupportedOptionsCount();

if (PrettyVersions::getVersion('sentry/sentry')->getPrettyVersion() !== '2.0.0') {
++$expectedCount;
Expand All @@ -38,7 +38,7 @@ public function testInvalidDataProviderIsMappingTheRightNumberOfOptions(): void
$supportedOptions = \array_unique(\array_column($providerData, 0));

$this->assertCount(
self::SUPPORTED_SENTRY_OPTIONS_COUNT,
$this->getSupportedOptionsCount(),
$supportedOptions,
'Provider for invalid configuration options mismatch: ' . PHP_EOL . print_r($supportedOptions, true)
);
Expand Down Expand Up @@ -76,6 +76,10 @@ public function testConfigurationDefaults(): void
$expectedDefaults['options']['in_app_exclude'][1] = '%kernel.project_dir%/vendor';
}

if ($this->classSerializersAreSupported()) {
$expectedDefaults['options']['class_serializers'] = [];
}

$this->assertEquals($expectedDefaults, $processed);
$this->assertArrayNotHasKey('server_name', $processed['options'], 'server_name has to be fetched at runtime, not before (see #181)');
}
Expand Down Expand Up @@ -127,6 +131,10 @@ public function optionValuesProvider(): array
$options[] = ['capture_silenced_errors', true];
}

if ($this->classSerializersAreSupported()) {
$options[] = ['class_serializers', ['count']];
}

return $options;
}

Expand Down Expand Up @@ -154,6 +162,10 @@ public function invalidValuesProvider(): array
['before_send', [$this, 'is not a callable']],
['before_send', false],
['before_send', -1],
['class_serializers', 'this is not a callable'],
['class_serializers', [$this, 'is not a callable']],
['class_serializers', false],
['class_serializers', -1],
['context_lines', -1],
['context_lines', 99999],
['context_lines', 'string'],
Expand Down
21 changes: 18 additions & 3 deletions test/DependencyInjection/SentryExtensionTest.php
Expand Up @@ -3,12 +3,12 @@
namespace Sentry\SentryBundle\Test\DependencyInjection;

use Jean85\PrettyVersions;
use PHPUnit\Framework\TestCase;
use Sentry\Breadcrumb;
use Sentry\Event;
use Sentry\Integration\IntegrationInterface;
use Sentry\Options;
use Sentry\SentryBundle\DependencyInjection\SentryExtension;
use Sentry\SentryBundle\Test\BaseTestCase;
use Symfony\Component\DependencyInjection\Alias;
use Symfony\Component\DependencyInjection\Container;
use Symfony\Component\DependencyInjection\ContainerBuilder;
Expand All @@ -17,7 +17,7 @@
use Symfony\Component\HttpFoundation\RequestStack;
use Symfony\Component\HttpKernel\Kernel;

class SentryExtensionTest extends TestCase
class SentryExtensionTest extends BaseTestCase
{
private const OPTIONS_TEST_PUBLIC_ALIAS = 'sentry.options.public_alias';

Expand All @@ -34,7 +34,7 @@ public function testDataProviderIsMappingTheRightNumberOfOptions(): void
}

$this->assertCount(
$expectedCount,
$this->getSupportedOptionsCount(),
$supportedOptions,
'Provider for configuration options mismatch: ' . PHP_EOL . print_r($supportedOptions, true)
);
Expand Down Expand Up @@ -138,6 +138,16 @@ public function optionsValueProvider(): array
$options[] = ['capture_silenced_errors', true, 'shouldCaptureSilencedErrors'];
}

if ($this->classSerializersAreSupported()) {
$options['class_serializer'] = [
'class_serializers',
[
self::class => __NAMESPACE__ . '\mockClassSerializer',
],
'getClassSerializers',
];
}

return $options;
}

Expand Down Expand Up @@ -375,6 +385,11 @@ function mockBeforeBreadcrumb(Breadcrumb $breadcrumb): ?Breadcrumb
return null;
}

function mockClassSerializer($object)
{
return ['value' => 'serialized_class'];
}

class CallbackMock
{
public static function callback()
Expand Down