Skip to content

fix Pre Hook Exception in case _controller is not stringable #366

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

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

trigrab
Copy link

@trigrab trigrab commented May 10, 2025

@trigrab trigrab requested a review from a team as a code owner May 10, 2025 11:59
Copy link

welcome bot commented May 10, 2025

Thanks for opening your first pull request! If you haven't yet signed our Contributor License Agreement (CLA), then please do so that we can accept your contribution. A link should appear shortly in this PR if you have not already signed one.

Copy link

linux-foundation-easycla bot commented May 10, 2025

CLA Signed


The committers listed above are authorized under a signed CLA.

Comment on lines +51 to +63
if (is_string($controller)) {
$controllerName = $controller;
} elseif (is_array($controller) && is_object($controller[0]) && isset($controller[1])) {
// [$object, 'method']
$controllerName = get_class($controller[0]) . '::' . $controller[1];
} elseif (is_array($controller) && is_string($controller[0]) && isset($controller[1])) {
// ['ClassName', 'method']
$controllerName = $controller[0] . '::' . $controller[1];
} elseif (is_object($controller)) {
$controllerName = get_class($controller);
} else {
$controllerName = 'sub-request';
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Suggested change
if (is_string($controller)) {
$controllerName = $controller;
} elseif (is_array($controller) && is_object($controller[0]) && isset($controller[1])) {
// [$object, 'method']
$controllerName = get_class($controller[0]) . '::' . $controller[1];
} elseif (is_array($controller) && is_string($controller[0]) && isset($controller[1])) {
// ['ClassName', 'method']
$controllerName = $controller[0] . '::' . $controller[1];
} elseif (is_object($controller)) {
$controllerName = get_class($controller);
} else {
$controllerName = 'sub-request';
}
if (!is_callable($controller, true, $controllerName)) {
$controllerName = 'sub-request';
}

Copy link
Author

Choose a reason for hiding this comment

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

I like your suggestion, as it is cleaner. I am just not certain if we can assume that every controller out there passes the is_callable check.
But I don't want to create an academic discussion here and therefor slow down this fix.
Can you maybe just elaborate a bit on your suggestion?

Copy link
Contributor

Choose a reason for hiding this comment

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

is_callable is only slightly stricter than the if-else statements: it additionally checks whether arrays have exactly two elements and whether objects implement ::__invoke(). (Anything that fails the is_callable() check should also cause an exception in the default ControllerResolver.)

FWIW it might make sense to listen to ControllerEvent/ControllerArgumentsEvent instead of relying on the _controller attribute to have access to the final controller callable that will be invoked.

Choose a reason for hiding this comment

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

The problem with applying this suggestion is that there is no $controllerName when it is a callable.

But I think you are right in suggesting to listen to an event (or hooking to the end of the dispatch method - I'm not familiar with C-level PHP, so can't see what is possible and makes sense). The moment the actual controller is definitely resolved is when returning from the dispatching of the ControllerArgumentsEvent. At this point it is also guaranteed that the controller is callable (Symfony will throw an exception if it is not, but this should hopefully only ever happen in a dev environment, so should be ok to ignore here). This would avoid getting problems with any custom logic.

But looking at the resolved callable would mean that the original if-else construct in the PR is needed to get meaningful values.

Copy link
Contributor

Choose a reason for hiding this comment

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

that there is no $controllerName when it is a callable

is_callable() sets $controllerName

Copy link
Author

Choose a reason for hiding this comment

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

@Nevay that means you still think your suggestion is the best solution?

I want to move this forward. If you think that is the best solution I will apply it so that we can go on.

Copy link
Collaborator

Choose a reason for hiding this comment

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

I think you should try Nevay's suggestion, and add integration tests to confirm all the variances of $controller work as expected

Copy link

codecov bot commented May 19, 2025

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 79.45%. Comparing base (e201e11) to head (bdec4e5).
Report is 3 commits behind head on main.

Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##               main     #366      +/-   ##
============================================
- Coverage     82.17%   79.45%   -2.73%     
+ Complexity     1870      730    -1140     
============================================
  Files           137       54      -83     
  Lines          7822     2696    -5126     
============================================
- Hits           6428     2142    -4286     
+ Misses         1394      554     -840     
Flag Coverage Δ
Aws 92.59% <ø> (ø)
Context/Swoole 0.00% <ø> (ø)
Instrumentation/CakePHP 20.27% <ø> (ø)
Instrumentation/CodeIgniter ?
Instrumentation/Curl ?
Instrumentation/Doctrine 92.77% <ø> (ø)
Instrumentation/ExtAmqp 89.26% <ø> (ø)
Instrumentation/ExtRdKafka ?
Instrumentation/Guzzle ?
Instrumentation/HttpAsyncClient ?
Instrumentation/IO ?
Instrumentation/Laravel ?
Instrumentation/MongoDB 74.28% <ø> (ø)
Instrumentation/MySqli ?
Instrumentation/OpenAIPHP ?
Instrumentation/PDO ?
Instrumentation/Psr14 ?
Instrumentation/Psr15 ?
Instrumentation/Psr16 ?
Instrumentation/Psr18 ?
Instrumentation/Psr3 ?
Instrumentation/Psr6 ?
Instrumentation/Slim ?
Instrumentation/Symfony ?
Instrumentation/Yii ?
Logs/Monolog 100.00% <ø> (ø)
Propagation/ServerTiming 100.00% <ø> (ø)
Propagation/TraceResponse 100.00% <ø> (ø)
ResourceDetectors/Azure 91.66% <ø> (ø)
ResourceDetectors/Container 93.02% <ø> (ø)
Sampler/RuleBased 33.51% <ø> (ø)
Shims/OpenTracing 92.45% <ø> (ø)
Symfony ?
Utils/Test 87.53% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

see 83 files with indirect coverage changes


Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e201e11...bdec4e5. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[opentelemetry-php-contrib] Pre hook exception Symfony\Component\HttpKernel\Controller\ErrorController could not be converted to string
4 participants