Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions src/Integration/FilterExceptionEvent.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Frosh\SentryBundle\Integration;

use Sentry\ExceptionDataBag;
use Symfony\Contracts\EventDispatcher\Event;

class FilterExceptionEvent extends Event
{

/**
* @param ExceptionDataBag[] $exceptions
*/
public function __construct(private array $exceptions)
{
}

/**
* @return ExceptionDataBag[]
*/
public function getExceptions(): array
{
return $this->exceptions;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.

/**
* @param ExceptionDataBag[] $exceptions
*/
public function setExceptions(array $exceptions): void
{
$this->exceptions = $exceptions;
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.



}
29 changes: 10 additions & 19 deletions src/Integration/UseShopwareExceptionIgnores.php
Original file line number Diff line number Diff line change
Expand Up @@ -5,34 +5,25 @@
use Sentry\Event;
use Sentry\Integration\IntegrationInterface;
use Sentry\State\Scope;
use Symfony\Contracts\EventDispatcher\EventDispatcherInterface;

class UseShopwareExceptionIgnores implements IntegrationInterface
{
/**
* @param array<string, array{log_level: string}> $exceptions
*/
public function __construct(private readonly array $exceptions) {}
public function __construct(private readonly EventDispatcherInterface $eventDispatcher)
{
}

public function setupOnce(): void
{
$exceptions = $this->exceptions;

Scope::addGlobalEventProcessor(function (Event $event) use ($exceptions): ?Event {
$eventExceptions = $event->getExceptions()[0] ?? null;
$eventDispatcher = $this->eventDispatcher;

if ($eventExceptions === null) {
Scope::addGlobalEventProcessor(static function (Event $event) use ($eventDispatcher): ?Event {

Check failure on line 20 in src/Integration/UseShopwareExceptionIgnores.php

View workflow job for this annotation

GitHub Actions / phpstan

Anonymous function never returns null so it can be removed from the return type.

Check failure on line 20 in src/Integration/UseShopwareExceptionIgnores.php

View workflow job for this annotation

GitHub Actions / phpstan

Anonymous function never returns null so it can be removed from the return type.
$exceptions = $event->getExceptions();
if (empty($exceptions)) {
return $event;
}

$config = $exceptions[$eventExceptions->getType()] ?? [];

if (!isset($config['log_level'])) {
return $event;
}

if ($config['log_level'] === 'notice') {
return null;
}
$exceptions = $eventDispatcher->dispatch(new FilterExceptionEvent($exceptions))->getExceptions();
$event->setExceptions($exceptions);
Comment on lines +25 to +26
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Verification agent

🧩 Analysis chain

Ensure type safety when setting exceptions.

The static analysis indicates a type mismatch. While the code will work at runtime, it's better to ensure proper typing.

The getExceptions() method returns an array that should contain ExceptionDataBag objects. Let me verify the return type declaration:


🏁 Script executed:

#!/bin/bash
# Description: Check the return type of FilterExceptionEvent::getExceptions()

# Search for the getExceptions method definition
ast-grep --pattern $'class FilterExceptionEvent {
  $$$
  public function getExceptions(): $_
  $$$
}'

Length of output: 103


Let’s locate the actual FilterExceptionEvent class and its getExceptions() signature:


🏁 Script executed:

#!/bin/bash
# 1. Find where FilterExceptionEvent is defined
rg "class FilterExceptionEvent" -n .

# 2. Find all occurrences of getExceptions to see its return type
rg "function getExceptions" -n .

Length of output: 248


Annotate exception array types for static analysis

Static analysis warns that getExceptions() returns a plain array, which makes downstream assignments to ExceptionDataBag[] untyped. Add PHPDoc annotations so tools like PHPStan/Psalm know this array holds ExceptionDataBag instances.

• src/Integration/FilterExceptionEvent.php
– Line 20: add a PHPDoc @return ExceptionDataBag[] above getExceptions(): array.
– Line 24: add a PHPDoc @param ExceptionDataBag[] $exceptions above setExceptions(array $exceptions): void.

• src/Integration/UseShopwareExceptionIgnores.php
– Line 27 (just before assignment): annotate the local variable as /** @var ExceptionDataBag[] $exceptions */.

Example diff:

--- a/src/Integration/FilterExceptionEvent.php
+++ b/src/Integration/FilterExceptionEvent.php
@@
-    public function getExceptions(): array
+    /**
+     * @return ExceptionDataBag[]
+     */
+    public function getExceptions(): array
@@
-    public function setExceptions(array $exceptions): void
+    /**
+     * @param ExceptionDataBag[] $exceptions
+     */
+    public function setExceptions(array $exceptions): void
--- a/src/Integration/UseShopwareExceptionIgnores.php
+++ b/src/Integration/UseShopwareExceptionIgnores.php
@@ -25,6 +25,7 @@
             // …
-            $exceptions = $eventDispatcher->dispatch(new FilterExceptionEvent($exceptions))->getExceptions();
+            /** @var ExceptionDataBag[] $exceptions */
+            $exceptions = $eventDispatcher->dispatch(new FilterExceptionEvent($exceptions))->getExceptions();
             $event->setExceptions($exceptions);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$exceptions = $eventDispatcher->dispatch(new FilterExceptionEvent($exceptions))->getExceptions();
$event->setExceptions($exceptions);
// …
/** @var ExceptionDataBag[] $exceptions */
$exceptions = $eventDispatcher->dispatch(new FilterExceptionEvent($exceptions))->getExceptions();
$event->setExceptions($exceptions);
🧰 Tools
🪛 PHPStan (2.1.15)

28-28: Parameter #1 $exceptions of method Sentry\Event::setExceptions() expects array<Sentry\ExceptionDataBag>, array given.

(argument.type)

🤖 Prompt for AI Agents
In src/Integration/UseShopwareExceptionIgnores.php around lines 27 to 28, the
variable $exceptions assigned from getExceptions() lacks explicit type
annotation, causing static analysis warnings about type safety. To fix this, add
a PHPDoc comment just before the assignment to annotate $exceptions as an array
of ExceptionDataBag objects (/** @var ExceptionDataBag[] $exceptions */). This
will ensure proper typing for static analysis tools and maintain type safety.


return $event;
});
Expand Down
8 changes: 8 additions & 0 deletions src/Resources/config/packages/sentry.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
sentry:
options:
ignore_exceptions:
- 'Shopware\Storefront\Framework\Routing\Exception\SalesChannelMappingException'
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could be configured in the core as a shopware pull request and would automatically picked up by https://github.com/FriendsOfShopware/shopware-sentry-bundle/blob/main/src/Integration/UseShopwareExceptionIgnores.php ?

vendor/shopware/core/Framework/Resources/config/packages/framework.yaml:85

- 'Shopware\Core\Framework\Api\Controller\Exception\AuthThrottledException'
- 'Shopware\Core\Framework\RateLimiter\Exception\RateLimitExceededException'
- 'Symfony\Component\Console\Exception\CommandNotFoundException'
- 'League\OAuth2\Server\Exception\OAuthServerException'
Comment on lines +1 to +8
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure... feels weird to configure a third party bundle here. What do you think?

Copy link
Copy Markdown
Contributor

@amenk amenk Jun 13, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah but probably there is no other possibility as we cannot really influence League\OAuth2 ? Sounds legit to me.

31 changes: 30 additions & 1 deletion src/ShopwareSentryBundle.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,18 @@
use Frosh\SentryBundle\Integration\UseShopwareExceptionIgnores;
use Frosh\SentryBundle\Listener\FixRequestUrlListener;
use Frosh\SentryBundle\Listener\SalesChannelContextListener;
use Frosh\SentryBundle\Subscriber\FilterShopwareExceptionIgnoresSubscriber;
use Frosh\SentryBundle\Subscriber\FlowLogSubscriber;
use Frosh\SentryBundle\Subscriber\ScheduledTaskSubscriber;
use Shopware\Core\System\SalesChannel\Event\SalesChannelContextCreatedEvent;
use Symfony\Component\Config\FileLocator;
use Symfony\Component\Config\Loader\DelegatingLoader;
use Symfony\Component\Config\Loader\LoaderResolver;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Extension\ExtensionInterface;
use Symfony\Component\DependencyInjection\Loader\DirectoryLoader;
use Symfony\Component\DependencyInjection\Loader\GlobFileLoader;
use Symfony\Component\DependencyInjection\Loader\YamlFileLoader;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\HttpKernel\Bundle\Bundle;
use Symfony\Component\HttpKernel\Event\RequestEvent;
Expand All @@ -21,6 +28,8 @@ class ShopwareSentryBundle extends Bundle
{
public function build(ContainerBuilder $container): void
{
$this->loadConfiguration($container);

$container
->register(SalesChannelContextListener::class)
->addTag('kernel.event_listener', ['event' => SalesChannelContextCreatedEvent::class, 'method' => '__invoke'])
Expand All @@ -37,14 +46,19 @@ public function build(ContainerBuilder $container): void

$container
->register(UseShopwareExceptionIgnores::class)
->addArgument('%frosh_sentry.exclude_exceptions%');
->addArgument(new Reference('event_dispatcher'));

$container
->register(ScheduledTaskSubscriber::class)
->addArgument(new Reference('scheduled_task.repository'))
->addArgument('%frosh_sentry.report_scheduled_tasks%')
->addTag('kernel.event_subscriber');

$container
->register(FilterShopwareExceptionIgnoresSubscriber::class)
->addArgument('%frosh_sentry.exclude_exceptions%')
->addTag('kernel.event_subscriber');

$container
->register(FlowLogSubscriber::class)
->addTag('kernel.event_subscriber');
Expand All @@ -56,4 +70,19 @@ public function getContainerExtension(): ExtensionInterface
{
return new FroshSentryExtension();
}

private function loadConfiguration(ContainerBuilder $container): void
{
$locator = new FileLocator('Resources/config');
$resolver = new LoaderResolver([
new YamlFileLoader($container, $locator),
new GlobFileLoader($container, $locator),
new DirectoryLoader($container, $locator),
]);

$configLoader = new DelegatingLoader($resolver);
$confDir = \rtrim($this->getPath(), '/') . '/Resources/config';
$configLoader->load($confDir . '/{packages}/*.yaml', 'glob');

}
}
41 changes: 41 additions & 0 deletions src/Subscriber/FilterShopwareExceptionIgnoresSubscriber.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?php

namespace Frosh\SentryBundle\Subscriber;

use Frosh\SentryBundle\Integration\FilterExceptionEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class FilterShopwareExceptionIgnoresSubscriber implements EventSubscriberInterface
{

public function __construct(private readonly array $shopwareExceptionConfig)

Check failure on line 11 in src/Subscriber/FilterShopwareExceptionIgnoresSubscriber.php

View workflow job for this annotation

GitHub Actions / phpstan

Method Frosh\SentryBundle\Subscriber\FilterShopwareExceptionIgnoresSubscriber::__construct() has parameter $shopwareExceptionConfig with no value type specified in iterable type array.

Check failure on line 11 in src/Subscriber/FilterShopwareExceptionIgnoresSubscriber.php

View workflow job for this annotation

GitHub Actions / phpstan

Method Frosh\SentryBundle\Subscriber\FilterShopwareExceptionIgnoresSubscriber::__construct() has parameter $shopwareExceptionConfig with no value type specified in iterable type array.
{
}

public static function getSubscribedEvents()
{
return [
FilterExceptionEvent::class => 'filterSentryExceptions',
];
}


public function filterSentryExceptions(FilterExceptionEvent $event): void
{
$filteredExceptions = [];
foreach ($event->getExceptions() as $exception) {

$exceptionLogLevel = $this->shopwareExceptionConfig[$exception->getType()]['log_level'] ?? null;

if ($exceptionLogLevel === 'notice') {
continue;
}

$filteredExceptions[] = $exception;
}

$event->setExceptions($filteredExceptions);


}
}
Loading