Files
codebase-memory-mcp/tests
Martin Vogel 4e490bef5a fix(routes): HANDLES for Laravel array and invokable controller actions
Why: Laravel names a route's controller as [UserController::class, 'show'],
or, for an invokable controller, as GetCurrentUserController::class. The
route handler scan only took identifiers and strings, so these routes never
got a HANDLES edge. The cross-repo HTTP matcher reaches a route's handler
through that edge, so apps written this way - the #1146 reporter's app
among them - produced 0 CROSS_HTTP_CALLS. Resolving the class by short name
is not enough either: the call pass's import map bound `use
App\Http\Controllers\UserController` to Admin\UserController by name, even
with a composer.json PSR-4 map present, and the generic resolver's
multi-candidate fallback bound a vendor controller's show() to another
class's show().

Fix:
- extract_calls.c: for PHP, [X::class, 'm'] becomes the handler reference
  "Ns\X::m" and X::class becomes "Ns\X::__invoke". X is qualified the way PHP
  resolves it: through the file's `use` imports (aliases included), else
  the file namespace; a leading backslash is already absolute.
- registry.c, cbm_registry_resolve_handler (both route passes): a
  class-qualified handler is placed on a method QN only by what places the
  class file - the composer.json PSR-4 root in the package map, else the one
  candidate whose folders mirror the namespace (App\Http\Controllers ->
  app/Http/Controllers). A class that is not in the repo gets no handler.
  A handler reference without "::" resolves exactly as before.

Proof (release CLI built from this tree vs origin/main 1f9b4db1):
- laravel.io: HANDLES 0 -> 4, one for each of the 5 route registrations
  main mints (two share a Route). The use statement tells
  Articles\ArticlesController apart from Admin\ArticlesController.
  Route count unchanged (39). With the slashless-path and withRouting
  fixes also applied: HANDLES 0 -> 58, all from PHP controllers, samples
  checked against source (aliased AdminArticlesController and
  AdminUsersController included); the 7 routes left without a handler use
  methods from a vendor trait (AuthenticatesUsers).
- Reporter-shaped cross-repo check (Laravel 11 withRouting api:, invokable
  GetCurrentUserController under prefix('/users'), TS fetch('/api/users/me')):
  CROSS_HTTP_CALLS 0 with this fix alone (route /users/me, no /api mount) and
  0 with the withRouting fix alone (no HANDLES); 2 with both applied.
- krayin/laravel-crm (reduced to one route file): / <- Webkul\Admin\Http\
  Controllers\Controller::redirectToLogin, placed through the PSR-4 root
  Webkul\Admin\ -> packages/Webkul/Admin/src.

Tests (edge_types_probe): handles_laravel_class_handlers_issue1146,
handles_laravel_class_handlers_parallel_issue1146 and
handles_laravel_class_handlers_no_composer_issue1146 assert the exact HANDLES
set. They include controls for a same-named Admin\UserController::show, an
alias import, an unimported fully-qualified class, a package under a PSR-4
root whose folder does not mirror its namespace, a decoy __invoke, and two
vendor controllers that must get no edge. RED on origin/main 3x, green, RED
on revert. edge_types_probe, php_lsp, pipeline, parallel, route_canon and
cross_repo pass (730); make lint-ci passes.

Refs #1146

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
2026-10-04 20:46:42 +02:00
..