Skip to content

Commit 426ce3e

Browse files
Fix deprecation notice in route name extraction (#543)
Co-authored-by: Alex Bouma <alex@bouma.me>
1 parent 5ae05c8 commit 426ce3e

File tree

4 files changed

+109
-39
lines changed

4 files changed

+109
-39
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22

33
## Unreleased
44

5+
- Fix deprecation notice in route name extraction (#543)
6+
57
## 2.11.0
68

79
- Add support for Laravel 9 (#534)

src/Sentry/Laravel/EventHandler.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -279,7 +279,7 @@ public function __call($method, $arguments)
279279
*/
280280
protected function routerMatchedHandler(Route $route)
281281
{
282-
$routeName = Integration::extractNameForRoute($route) ?? '<unlabeled transaction>';
282+
$routeName = Integration::extractNameForRoute($route);
283283

284284
Integration::addBreadcrumb(new Breadcrumb(
285285
Breadcrumb::LEVEL_INFO,

src/Sentry/Laravel/Integration.php

Lines changed: 44 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -30,15 +30,15 @@ class Integration implements IntegrationInterface
3030
*/
3131
public function setupOnce(): void
3232
{
33-
Scope::addGlobalEventProcessor(function (Event $event): Event {
33+
Scope::addGlobalEventProcessor(static function (Event $event): Event {
3434
$self = SentrySdk::getCurrentHub()->getIntegration(self::class);
3535

3636
if (!$self instanceof self) {
3737
return $event;
3838
}
3939

4040
if (empty($event->getTransaction())) {
41-
$event->setTransaction($self->getTransaction());
41+
$event->setTransaction(self::getTransaction());
4242
}
4343

4444
return $event;
@@ -121,52 +121,64 @@ public static function flushEvents(): void
121121
*
122122
* @param \Illuminate\Routing\Route $route
123123
*
124-
* @return string|null
124+
* @return string
125125
*/
126-
public static function extractNameForRoute(Route $route): ?string
126+
public static function extractNameForRoute(Route $route): string
127127
{
128128
$routeName = null;
129129

130-
if (empty($routeName) && $route->getName()) {
131-
// someaction (route name/alias)
132-
$routeName = $route->getName();
133-
134-
// Laravel 7 route caching generates a route names if the user didn't specify one
135-
// theirselfs to optimize route matching. These route names are useless to the
136-
// developer so if we encounter a generated route name we discard the value
137-
if (Str::contains($routeName, 'generated::')) {
138-
$routeName = null;
139-
}
140-
141-
// If the route name ends with a `.` we assume an incomplete group name prefix
142-
// we discard this value since it will most likely not mean anything to the
143-
// developer and will be duplicated by other unnamed routes in the group
144-
if (Str::endsWith($routeName, '.')) {
145-
$routeName = null;
146-
}
130+
// someaction (route name/alias)
131+
if ($route->getName()) {
132+
$routeName = self::extractNameForNamedRoute($route->getName());
147133
}
148134

135+
// Some\Controller@someAction (controller action)
149136
if (empty($routeName) && $route->getActionName()) {
150-
// Some\Controller@someAction (controller action)
151-
$routeName = ltrim($route->getActionName(), '\\');
152-
153-
$baseNamespace = self::$baseControllerNamespace ?? '';
154-
155-
// Strip away the base namespace from the action name
156-
if (!empty($baseNamespace)) {
157-
// @see: Str::after, but this is not available before Laravel 5.4 so we use a inlined version
158-
$routeName = array_reverse(explode($baseNamespace . '\\', $routeName, 2))[0];
159-
}
137+
$routeName = self::extractNameForActionRoute($route->getActionName());
160138
}
161139

140+
// /someaction // Fallback to the url
162141
if (empty($routeName) || $routeName === 'Closure') {
163-
// /someaction // Fallback to the url
164142
$routeName = '/' . ltrim($route->uri(), '/');
165143
}
166144

167145
return $routeName;
168146
}
169147

148+
private static function extractNameForNamedRoute(string $routeName): ?string
149+
{
150+
// Laravel 7 route caching generates a route names if the user didn't specify one
151+
// theirselfs to optimize route matching. These route names are useless to the
152+
// developer so if we encounter a generated route name we discard the value
153+
if (Str::contains($routeName, 'generated::')) {
154+
return null;
155+
}
156+
157+
// If the route name ends with a `.` we assume an incomplete group name prefix
158+
// we discard this value since it will most likely not mean anything to the
159+
// developer and will be duplicated by other unnamed routes in the group
160+
if (Str::endsWith($routeName, '.')) {
161+
return null;
162+
}
163+
164+
return $routeName;
165+
}
166+
167+
private static function extractNameForActionRoute(string $actionName): string
168+
{
169+
$routeName = ltrim($actionName, '\\');
170+
171+
$baseNamespace = self::$baseControllerNamespace ?? '';
172+
173+
if (empty($baseNamespace)) {
174+
return $routeName;
175+
}
176+
177+
// Strip away the base namespace from the action name
178+
// @see: Str::after, but this is not available before Laravel 5.4 so we use a inlined version
179+
return array_reverse(explode($baseNamespace . '\\', $routeName, 2))[0];
180+
}
181+
170182
/**
171183
* Retrieve the meta tags with tracing information to link this request to front-end requests.
172184
*

test/Sentry/IntegrationTest.php

Lines changed: 62 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,7 @@ public function testTransactionIsSetWhenRouteMatchedEventIsFired(): void
2929
Integration::setTransaction(null);
3030

3131
$event = new RouteMatched(
32-
new Route('GET', $routeUrl = '/sentry-route-matched-event', static function () {
33-
// do nothing...
34-
}),
32+
new Route('GET', $routeUrl = '/sentry-route-matched-event', []),
3533
Mockery::mock(Request::class)->makePartial()
3634
);
3735

@@ -45,9 +43,7 @@ public function testTransactionIsSetWhenRouterMatchedEventIsFired(): void
4543
Integration::setTransaction(null);
4644

4745
$this->dispatchLaravelEvent('router.matched', [
48-
new Route('GET', $routeUrl = '/sentry-router-matched-event', static function () {
49-
// do nothing...
50-
}),
46+
new Route('GET', $routeUrl = '/sentry-router-matched-event', []),
5147
]);
5248

5349
$this->assertSame($routeUrl, Integration::getTransaction());
@@ -106,4 +102,64 @@ public function testTransactionIsNotAppliedToEventWhenTransactionIsAlreadySet():
106102
$this->assertSame($eventTransaction, $event->getTransaction());
107103
});
108104
}
105+
106+
public function testExtractingNameForRouteWithName(): void
107+
{
108+
$route = (new Route('GET', '/foo', []))->name($routeName = 'foo-bar');
109+
110+
$this->assertSame($routeName, Integration::extractNameForRoute($route));
111+
}
112+
113+
public function testExtractingNameForRouteWithAction(): void
114+
{
115+
$route = (new Route('GET', '/foo', [
116+
'controller' => $controller = 'SomeController@someAction',
117+
]));
118+
119+
$this->assertSame($controller, Integration::extractNameForRoute($route));
120+
}
121+
122+
public function testExtractingNameForRouteWithoutName(): void
123+
{
124+
$route = new Route('GET', $url = '/foo', []);
125+
126+
$this->assertSame($url, Integration::extractNameForRoute($route));
127+
}
128+
129+
public function testExtractingNameForRouteWithActionAndName(): void
130+
{
131+
$route = (new Route('GET', '/foo', [
132+
'controller' => 'SomeController@someAction',
133+
]))->name($routeName = 'foo-bar');
134+
135+
$this->assertSame($routeName, Integration::extractNameForRoute($route));
136+
}
137+
138+
public function testExtractingNameForRouteWithAutoGeneratedName(): void
139+
{
140+
// We fake a generated name here, Laravel generates them each starting with `generated::`
141+
$route = (new Route('GET', $url = '/foo', []))->name('generated::KoAePbpBofo01ey4');
142+
143+
$this->assertSame($url, Integration::extractNameForRoute($route));
144+
}
145+
146+
public function testExtractingNameForRouteWithIncompleteGroupName(): void
147+
{
148+
$route = (new Route('GET', $url = '/foo', []))->name('group-name.');
149+
150+
$this->assertSame($url, Integration::extractNameForRoute($route));
151+
}
152+
153+
public function testExtractingNameForRouteWithStrippedBaseNamespaceFromAction(): void
154+
{
155+
Integration::setControllersBaseNamespace('BaseNamespace');
156+
157+
$route = (new Route('GET', '/foo', [
158+
'controller' => 'BaseNamespace\\SomeController@someAction',
159+
]));
160+
161+
$this->assertSame('SomeController@someAction', Integration::extractNameForRoute($route));
162+
163+
Integration::setControllersBaseNamespace(null);
164+
}
109165
}

0 commit comments

Comments
 (0)