Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Router Laravel Package

poshtive/router

Convention-based route discovery for Laravel controllers. Public methods become routes automatically, with PHP attributes for HTTP verb overrides, middleware, where constraints, prefixes, and model-bound parameters. Supports Laravel 12/13 and PHP 8.3.

View on GitHub
Deep Wiki
Context7

Getting Started

Install and verify compatibility first.

composer require poshtive/router
php artisan vendor:publish --provider="Poshtive\Router\RouterServiceProvider" --tag="config"

Before anything else, confirm the declared requirements against your app: PHP ^8.3 and Laravel components ^13.0. This is the single biggest adoption gate — if you're on Laravel 10/11/12, stop here. Also reconcile the naming: the README badges and links point at qoqn/laravel-router while the install target is poshtive/router. Confirm the Packagist package name with composer show poshtive/router and skim vendor/poshtive/router/src before trusting the docs.

Where to look first — in this order:

  1. config/router.php — the five knobs (convention, method_extends, http_methods_map, report_skipped_routes, strict) decide almost everything about your daily experience.
  2. Poshtive\Router\Attributes\* — Route, Where, LocalOnly, DoNotDiscover, IgnoreParentMiddleware. These are your escape hatches.
  3. Poshtive\Router\Router::discover() — the only public entry point you'll call.

First use case — a scoped pilot, not a migration. Don't point discovery at your whole app/Http/Controllers on day one. Add one line to routes/web.php, targeting a single small subdirectory:

use Poshtive\Router\Router;

Router::create()->discover(app_path('Http/Controllers/Marketing'));

Then immediately run php artisan route:list --path=marketing and compare against what you expected. Start with a fresh, conventionally-shaped controller set (an IndexController plus one resource controller) rather than retrofitting existing controllers — you'll learn the path-construction rules in ten minutes instead of debugging them for a week.

Implementation Patterns

Pick one convention and enforce it repo-wide. Mixing prefix and attribute_or_get across teams produces routes that are impossible to grep for. prefix (getIndex, postStore, deleteDestroyApp) is self-documenting with zero attributes and is the better default for greenfield. attribute_or_get is the better fit for teams already writing clean REST method names — pair it with http_methods_map so store/update/destroy don't need a #[Route(method: ...)] on every method.

Layered middleware via abstract bases. The combination that actually pays off day-to-day:

#[DoNotDiscover]
#[Route(middleware: ['auth', 'verified'])]
abstract class AuthenticatedController extends Controller {}

class UserController extends AuthenticatedController {
    public function index() {}                 // GET /user, with auth+verified

    #[IgnoreParentMiddleware]
    public function show() {}                  // GET /user/show, no inherited middleware
}

Combine with method_extends => true for shared CRUD bases. Note the asymmetry: #[IgnoreParentMiddleware] on a class drops parent middleware but keeps the class's own; on a method it drops everything class-level.

Nested resources via child-controller folders. A User/ directory next to UserController produces /user/{user}/profile/.... This is the package's most opinionated feature — the rule is that every child controller method must take at least one Eloquent model parameter or registration fails. Adopt it only if your nested resources genuinely hang off a parent model.

Keep manual routes for non-conventional things. Webhooks, third-party callbacks, signed URLs, and anything with a fixed external path stay in routes/web.php or routes/api.php. There's nothing wrong with a hybrid file — the package explicitly supports it. Register discovered routes before any catch-all or wildcard routes so they aren't shadowed.

Constraints go on the method, not the parameter. #[Where('id', '\d+')] stacked multiple times; all constraints must pass. Use this to keep /user/{id}/show from swallowing /user/create in route matching order.

CI pattern: turn on strict => true and report_skipped_routes => true in your testing env, so duplicate registrations fail the build and silently-dropped controllers show up in logs. Keep strict => false locally if you want leniency during refactors.

Gotchas and Tips

  • Every public method becomes a route. This is the top source of accidental surface area. Helper methods you intended as internal must be private/protected, or the whole class needs #[DoNotDiscover].
  • Duplicates fail silently by default. With strict => false, collisions are only logged — and only if a logger is available. Two controllers mapping to the same VERB + URI will shadow each other with no visible error. Turn strict on before you have more than a handful of controllers.
  • Parameter ordering inverts your mental model. update(int $id, string $section) becomes /user/{id}/update/{section} — the model param jumps before the action name. Either adopt that shape consistently or reach for keepOrder: true, but don't mix.
  • method_extends defaults to false. Trait and parent-class methods are invisible until you flip it, and flipping it can double-register if the parent isn't marked #[DoNotDiscover]. Audit before enabling.
  • Class-level #[Route] only honors middleware. uri, method, and keepOrder on the class are ignored — a common wasted half-hour.
  • Only primitives and Eloquent models become parameters. Request, services, and value objects are dropped from the signature. That's usually what you want, but it means a method with only non-model params produces a route with no parameters at all.
  • #[LocalOnly] plus route caching is a trap. Run php artisan route:cache in a local environment and those dev-only routes get baked into the cached manifest. Always cache in the target environment, and add a deploy check that local-only paths 404 in staging/production.
  • Performance and caching. Discovery is a filesystem scan at boot. Confirm php artisan route:cache actually works with your setup and that route registration is deterministic (1.0.0 claims it is for tied priorities) — otherwise you're paying a directory walk on every request.
  • Debugging recipe: php artisan route:list --path=<segment> -v first, then a one-off tinker snippet instantiating Router::create() and dumping the discovered class list. There's no documented post-discovery event or naming hook, so if you need custom URI generation beyond the attributes, plan on a thin wrapper class rather than forking.
  • Overall assessment: the API surface is small, coherent, and well-documented — this is a genuinely usable convention router, and the strict/skip-reporting diagnostics show real production intent. But it's at 0 stars, 0 dependents, a single maintainer, and a Laravel 13 floor. Treat it as a pilot on a new project with conventional CRUD, not a retrofit into a large existing route file. Budget a half-day to read src/ before you depend on it, and keep your manual routes as the fallback path so extraction is cheap.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-notification
adachsoft/cli-process-tester
jhaskell13/laraflow
sebastienheyd/boilerplate-media-manager
ccast/tagixo-primix
pretendtrue/laravel-builder
sawmainek/laravel-scout-tntsearch-driver
tomshaw/laravel-calendar-table
dibakar/laravel-ownership
steadrun/laravel-monitor
labyrinthe/connect-laravel
elmogy/layan
drewdan/sentinel-client
dskripchenko/laravel-llm
fatryst/nuonuo
stevenay/myanfont
gmostafa/php-graphql-client
xeviant/paystack
snowsoft/faker
meditationsteps/blogetc