Files
codegraph/__tests__
Colby MchenryandClaude Opus 5.5 002dd4d517 feat(frameworks): CodeIgniter 3 routes, and calls through what $this->load loads (#3112)
A CodeIgniter 3 project had no routes in the graph and its flows stopped
at the controller: `$this->users_model->find($id)` goes through a property
nothing declares, so most such calls failed and the rest were guesses by
method name.

The resolver is detected by system/core/CodeIgniter.php, or by a routes
file naming a default controller, at any depth. It makes:
- a route per public method of a controller, implicit-public ones too,
  at /<folder>/<class>/<method>, and HMVC modules with the module first;
- a route per $route entry in routes.php, verb-scoped or not, and the
  default controller at /. `controller/method/$1` walks to the controller
  as CodeIgniter does, and a variable in the method's place binds the
  class;
- a `calls` edge for `$this->x->m()`, `$this->CI->x->m()` and
  `$CI->x->m()` to the method on the class x holds, its own or inherited.
  A class is read by name whatever the case, as PHP and the loader read
  it, and an alias comes from the load that gives it;
- a `calls` edge from `$this->load->view('a/b')` to the view's file, where
  the calls a template makes are recorded, so a request can be followed
  to the end.

Differences from PR #167, each from the real apps: its controller test
is a list of base classes, which misses EA_Controller, Secure_Controller
and every other project's own; its property match is PascalCase only,
which misses `$this->providers_model` and `$this->mdl_invoices`, the form
two of the four apps use throughout; and it stopped at a file-level
`imports` edge to the class, so the flow still ended at the controller.
A reference it made to a method by name could land on a same-named method
in another controller, so a route's reference here names its own file.

Validation:
- codeigniter.test.ts, 21 tests, on the kernel and the wasm path; the 10
  on a real index fail with the resolver unregistered.
- A/B on main cd04b21a, real CI3 apps: alextselegidis/easyappointments
  f6c8a4c2 +217 routes, +1,229 edges; InvoicePlane e5e2529d (HMVC) +213,
  +1,088; opensourcepos 3.3.9 c00ff28d +315, +1,428; ci-bonfire/Bonfire
  3eaf6f88 +67, +515. Classes: `+references framework` route to handler,
  `+calls framework` property call, and 2 `+calls test-request`. Nothing
  removed. Those 2 come from an existing pass: a vendored SimpleTest file
  calls `$this->get('http://www.lastcraft.com/')`, read as `/`, which now
  exists.
- Every route binds: 217/217, 213/213, 315/315, 67/67.
- Site by site, every framework edge read against its source line and the
  class the property holds: 1,012, 875, 1,113 and 446 edges, none wrong.
- A text scan of `->x->m(` where x names a project class: 967 of 967
  linked, 855 of 961, 886 of 891, 379 of 420. What's left is methods the
  class doesn't declare: InvoicePlane's are `where`, `update` and the like,
  which MY_Model forwards to the database through __call.
- Flow: Booking::register -> Appointments_model::save, and
  Appointments::store -> save -> validate.
- Controls flask 49943b5a and gin 0f09c3a9 are byte-identical.
- Index CPU, median of 3 interleaved, with a suite running: ospos +6.8%,
  easyappointments -8.2%, flask -9.1%, gin -8.8%. The swing is noise; a
  project that doesn't use CodeIgniter pays one path scan at detection.

Left out: routes.php entries a helper function adds, which only that
function's code says; CodeIgniter 4, a different layout.

Reimplements PR #167 by @darkspock.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-30 17:52:18 -05:00
..