Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Change matching method in ShopContextSubscriber#39837

Open
djbuch wants to merge 19 commits into
PrestaShop:developfrom
djbuch:patch-69
Open

Change matching method in ShopContextSubscriber#39837
djbuch wants to merge 19 commits into
PrestaShop:developfrom
djbuch:patch-69

Conversation

@djbuch
Copy link
Copy Markdown
Contributor

@djbuch djbuch commented Oct 26, 2025

Questions Answers
Branch? develop
Description? Fixed routing issue where using match() instead of matchRequest() caused the full Request object not to be passed to the router. This resulted in Symfony\Component\Routing\Matcher\Dumper\CompiledUrlMatcherTrait generating a "pseudo" request without headers, breaking route conditions that rely on request properties (e.g., request.isXmlHttpRequest() on the admin_emails_send_test route).
Type? bug fix
Category? CO
BC breaks? no
Deprecations? no
How to test? 1. Navigate to the email configuration page in the Back Office in a multishop environment
2. Try to send a test email using the AJAX request
3. Verify that the request is properly handled and the isXmlHttpRequest() condition is correctly evaluated
4. Check that routes with request-based conditions (like header checks) work as expected
UI Tests https://github.com/SiraDIOP/ga.tests.ui.pr/actions/runs/21753389591
Fixed issue or discussion? #37572, #39991
Related PRs
Sponsor company Web Premiere

@djbuch djbuch requested a review from a team as a code owner October 26, 2025 08:55
@github-project-automation github-project-automation Bot moved this to Ready for review in PR Dashboard Oct 26, 2025
@ps-jarvis ps-jarvis added develop Branch Bug fix Type: Bug fix labels Oct 26, 2025
@Progi1984 Progi1984 linked an issue Oct 26, 2025 that may be closed by this pull request
2 tasks
@Codencode
Copy link
Copy Markdown
Contributor

Codencode commented Nov 19, 2025

Hi @djbuch,
your solution has a few issues, do you think you can fix them?
I'm asking because I wanted to test it and see if we can include it directly in the 9.0.x branch.

[Edit]
I ran a test - if you restore the $router parameter to what it was before, meaning you declare it as Symfony\Component\Routing\RouterInterface, the issue should be resolved and your solution should work.

@djbuch
Copy link
Copy Markdown
Contributor Author

djbuch commented Nov 20, 2025

Hello, I made the change you said, let's wait and see the check results.

[Edit]
But I think we will have a problem since RouterInterface doesn't define matchRequest but this is the core change needed in this bug fix

@Codencode
Copy link
Copy Markdown
Contributor

Hello, I made the change you said, let's wait and see the check results.

[Edit] But I think we will have a problem since RouterInterface doesn't define matchRequest but this is the core change needed in this bug fix

Okay, even though I tested it quickly locally and it works, let's wait for the tests to be sure/safe

@djbuch
Copy link
Copy Markdown
Contributor Author

djbuch commented Nov 20, 2025

Yes the PHPStan tests failed

Error: Call to an undefined method Symfony\Component\Routing\RouterInterface::matchRequest().


Line src/PrestaShopBundle/EventListener/Admin/Context/ShopContextSubscriber.php


365 Call to an undefined method
Symfony\Component\Routing\RouterInterface::matchRequest().

@Codencode
Copy link
Copy Markdown
Contributor

@djbuch
Okay, sorry 🙏, you're right, that's clear.

You could try it this way:
Reset the type of the $router parameter to Symfony\Component\Routing\Router
and then here

PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber: ~

you can replace PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber: ~ with:

  PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber:
    autowire: true
    autoconfigure: true
    arguments:
      $router: '@router'

Let's check if it doesn't throw an error anymore, and then we'll ask the others for confirmation too.

@kpodemski
Copy link
Copy Markdown
Contributor

Hello

I checked the problem, and the code below helped:

$controller = $request->attributes->get('_controller');
if (!$controller || !str_contains($controller, '::')) {
    return null;
}

Could you guys check?

@djbuch
Copy link
Copy Markdown
Contributor Author

djbuch commented Nov 20, 2025

@kpodemski where should this code go ?

@kpodemski
Copy link
Copy Markdown
Contributor

kpodemski commented Nov 20, 2025

@djbuch
image

I haven't tested other bugs that were reported by @Codencode, I've only tested sending emails :)

If that works, then it also requires removing RouterInterface and adapting tests if needed

@djbuch
Copy link
Copy Markdown
Contributor Author

djbuch commented Nov 20, 2025

But the problem here is in the matching of the route. Because of "request.isXmlHttpRequest()" in the route definition.

@kpodemski
Copy link
Copy Markdown
Contributor

@djbuch I'm not sure about that, to me the problem was a mismatch in the route. After applying the changes I don't have any errors mentioned by @Codencode

@Codencode
Copy link
Copy Markdown
Contributor

@djbuch image

I haven't tested other bugs that were reported by @Codencode, I've only tested sending emails :)

If that works, then it also requires removing RouterInterface and adapting tests if needed

@kpodemski this solution works, I tested it for the cases that were causing issues and it's ok.
@djbuch it's also less impactful, I would take it into consideration!

@djbuch
Copy link
Copy Markdown
Contributor Author

djbuch commented Nov 20, 2025

@kpodemski yes but the missmatch is because of request.isXmlHttpRequest(), with your code we just don't get the ShopContext from the route.

But the route exists, it is defined so it should be found. You can see that if you remove the condition request.isXmlHttpRequest() on the route definition the original code works, but this is the problem if we want the condition ton work we need to pass all the request to the match, not only a mocked request as it is done with ->match($request->getPathInfo())

[EDIT] : Did you try it in multishop context ?

private readonly ShopConfigurationInterface $configuration,
private readonly MultistoreFeature $multistoreFeature,
private readonly RouterInterface $router,
private readonly Router $router,
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.

I think you should be able to replace this with RequestMatcherInterface the interface that implements the method you need. And the @router service correctly implements it

As much as possible we should favor using interfaces instead of explicit classes

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hello I already tried that : 4228f42 but the check failed

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Ok tried again and with forcing the argument this time, let's see

Comment on lines +62 to +66
PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber:
autowire: true
autoconfigure: true
arguments:
$router: '@router'
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.

The autowire and autoconfigure are already set as default values on this file (at the top of the file), so in theory you don't need to change this service definition

The autowiring should also be able to automatically inject the @router service (also check my other comment about using the appropriate interface) If by lack of chance the DI doesn't inject the service you expect to you can at most limit this modifications to only the arguments part

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.

@jolelievre
Hi Jonathan,
If we don't pass the $router: '@router' parameter to the service, we get this error:

Cannot autowire service "PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber": argument 
"$router" of method "__construct()" references class "Symfony\Component\Routing\Router" but no such service exists. 
Try changing the type-hint to one of its parents: interface "Symfony\Component\Routing\RouterInterface", interface 
"Symfony\Component\Routing\RequestContextAwareInterface", interface "Symfony\Component\Routing\Generator\UrlGeneratorInterface", 
or interface "Symfony\Component\Routing\Matcher\UrlMatcherInterface".

So apparently, the system can't inject Symfony\Component\Routing\Router, which is why I suggested modifying the service definition.

You're absolutely right that we can avoid re-adding autowire and autoconfigure - I was the one who led @djbuch to make that mistake.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Hello, tried without, and I need the arguments part. But as it is written for some other Services forcing arguments in the file I think I should keep

autowire: true
autoconfigure: true

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.

ok my bad, let's go with then

@jolelievre
Copy link
Copy Markdown
Contributor

Hi guys, the fix seems legit I didn't go in depth into the router matchRequest method but I understand the idea behind it and it does make sense that the full request will give better matching for advanced routing configuration that just passing the path

I just commented on how this could be done in a cleaner way by using RequestMatcherInterface , didn't test it but it should do the job and still keep clean code

{
try {
$routeInfo = $this->router->match($request->getPathInfo());
$routeInfo = $this->router->matchRequest($request);
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.

We discussed about this with @kpodemski and his approach is also interesting:

$controller = $request->attributes->get('_controller');

because this way of retrieving the controller is faster BUT it requires the RouterListener to have been executed as it's the one that will set this attribute. The trick thing here is that this subscriber is executed twice:

  • once before the router
  • once after the router

So we thought maybe both solutions could be mixed, to combine both performance and stability, something like:

// Try to get the controller already set on the request (if RouterListener was executed)
$controller = $request->attributes->get('_controller');
if (empty($controller)) {
    // If the attribute is not present yet we handle the matching ourselves and get the controller via routing info
    $routeInfo = $this->router->matchRequest($request);
    $controller = $routeInfo['_controller'];
}

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK with that, I added these lines

Comment on lines +62 to +66
PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber:
autowire: true
autoconfigure: true
arguments:
$router: '@router'
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.

ok my bad, let's go with then

}

private function mockRouter(): RouterInterface|MockObject
private function mockRouter(): Router|MockObject
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.

Can you try using the interface please as well? It should work

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

OK I did the change, seems to work

Copy link
Copy Markdown
Contributor

@jolelievre jolelievre left a comment

Choose a reason for hiding this comment

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

Thanks @djbuch and @kpodemski

@ps-jarvis ps-jarvis added the Waiting for QA Status: action required, waiting for test feedback label Nov 21, 2025
@ps-jarvis ps-jarvis moved this from Ready for review to To be tested in PR Dashboard Nov 21, 2025
Comment on lines +62 to +66
PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber:
autowire: true
autoconfigure: true
arguments:
$router: '@router'
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.

@jolelievre
Hi Jonathan,
If we don't pass the $router: '@router' parameter to the service, we get this error:

Cannot autowire service "PrestaShopBundle\EventListener\Admin\Context\ShopContextSubscriber": argument 
"$router" of method "__construct()" references class "Symfony\Component\Routing\Router" but no such service exists. 
Try changing the type-hint to one of its parents: interface "Symfony\Component\Routing\RouterInterface", interface 
"Symfony\Component\Routing\RequestContextAwareInterface", interface "Symfony\Component\Routing\Generator\UrlGeneratorInterface", 
or interface "Symfony\Component\Routing\Matcher\UrlMatcherInterface".

So apparently, the system can't inject Symfony\Component\Routing\Router, which is why I suggested modifying the service definition.

You're absolutely right that we can avoid re-adding autowire and autoconfigure - I was the one who led @djbuch to make that mistake.

@prestashop-issue-bot prestashop-issue-bot Bot added the Topwatchers Backlog prioritization: issue reported & followed by +6 people label Nov 21, 2025
@Progi1984 Progi1984 added this to the 9.1.0 milestone Nov 24, 2025
@Progi1984 Progi1984 modified the milestones: 9.1.0, 9.2.0 Dec 15, 2025
@SiraDIOP SiraDIOP self-assigned this Feb 6, 2026
@kpodemski kpodemski closed this Mar 14, 2026
@github-project-automation github-project-automation Bot moved this from To be tested to Closed in PR Dashboard Mar 14, 2026
@kpodemski kpodemski reopened this Mar 14, 2026
@github-project-automation github-project-automation Bot moved this from Closed to Reopened in PR Dashboard Mar 14, 2026
@kpodemski
Copy link
Copy Markdown
Contributor

Hello @djbuch

Could you rebase on 9.1.x branch? I'm not sure what happened, but this PR is still in QA, and we'd love to have it as soon as possible.

@kpodemski kpodemski changed the title [CO] Change matching method in ShopContextSubscriber Change matching method in ShopContextSubscriber Mar 14, 2026
@kpodemski kpodemski added Waiting for author Status: action required, waiting for author feedback and removed Waiting for QA Status: action required, waiting for test feedback labels Mar 14, 2026
@ps-jarvis ps-jarvis moved this from Reopened to Waiting for author in PR Dashboard Mar 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Bug fix Type: Bug fix develop Branch Topwatchers Backlog prioritization: issue reported & followed by +6 people Waiting for author Status: action required, waiting for author feedback

Projects

Status: Waiting for author

Development

Successfully merging this pull request may close these issues.

Multistore - Send test email doesn't work

7 participants