Dispatcher::set() created a new FilteredCallable and dropped any filters
already registered for that name. Re-apply the stored before/after filters
so remapping an event (for example map('start', ...)) keeps them.
Adds regression tests at the Dispatcher and Engine level.
Since v3.19.2 every string callback went through parseStringClassAndMethod(),
so routes and events mapped to a global function name threw
InvalidArgumentException. Call existing functions directly and keep the
Class->method / Class::method parsing as before.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Expose the opt-in as a Flight::set() key in the flight.views.* family. Engine applies it to View::$restrictToPath when the view is created, same as path and extension. Default remains false.
Restore getTemplate() and its existing test exactly as on master. Default behavior is unchanged: absolute paths still render and exists() never throws. With restrictToPath on, render(), fetch() and exists() only accept files that resolve inside the views path. A blocked file has its own error message, separate from "not found".
SimplePdo::fetchRow() returns null when there are no rows. Guard
PdoWrapper::fetchField() so empty queries return false instead of
calling getData() on null. Closes#726.
files autoload still registers Loader::autoload() so Flight::path() works. Composer PSR-4 already loads flight\*. Reset leftover path() dirs in AutoloadTest so LoaderTest can assert the exact list.
PR 709 dropped the Composer files entry for flight/autoload.php and that file returned early when vendor/autoload.php existed, so Loader::autoload() never registered. path() still added directories; namespaced app classes never loaded. Upgrades must not break that.