PHPackages                             thewunder/croute - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Framework](/categories/framework)
4. /
5. thewunder/croute

ActiveLibrary[Framework](/categories/framework)

thewunder/croute
================

Convention based routing for PHP

3.1.0(5mo ago)1317.4k↓18.3%2[2 issues](https://github.com/thewunder/croute/issues)MITPHPPHP &gt;=8.1CI passing

Since Sep 29Pushed 5mo ago1 watchersCompare

[ Source](https://github.com/thewunder/croute)[ Packagist](https://packagist.org/packages/thewunder/croute)[ RSS](/packages/thewunder-croute/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (8)Versions (20)Used By (0)

Croute
======

[](#croute)

[![Latest Version on Packagist](https://camo.githubusercontent.com/41d402aa5cfaddb02eb97675fb08767d5c85c259c32f725139589a6e831c9be6/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f74686577756e6465722f63726f7574652e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/thewunder/croute)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](LICENSE.txt)

Convention based routing for PHP based on Symfony components.

Croute is great because:

- You don't need to maintain a routing table
- Promotes consistent code organization
- Allows for customization through attributes and events

Install via Composer
--------------------

[](#install-via-composer)

Via the command line:

```
composer.phar require thewunder/croute ^2.0

```

Or add the following to the require section your composer.json:

```
"thewunder/croute": "^2.0"

```

Basics
------

[](#basics)

Your index.php should look something like this:

```
$router = Router::create($eventDispatcher, ['Your\\Controller\\Namespace'], $container, [$dependency1, $dependency2]);
$router->route($request);
```

Your controllers should look something like this:

```
namespace Your\Controller\Namespace

class IndexController extends Croute\Controller
{
    public function __construct($dependency1, $dependency2)
    {
        //...
    }

    /**
     * Will be available at http://yourdomain/
     * and require the "required" (body or querystring) request parameter
     */
    public function indexAction($required, $optional = null)
    {
        echo 'Crouter Controller'; //you can echo or return a symfony Response
    }

    /**
     * Available at http://yourdomain/test
     */
    public function testAction()
    {
        return new Response('Test Action');
    }
}
```

The name of the controller determines which url it appears as:

-  -&gt; Your\\Controller\\Namespace\\MyController::indexAction()
-  -&gt; Your\\Controller\\Namespace\\MyController::actionAction()

It supports nested namespaces so that:

-  -&gt; Your\\Controller\\Namespace\\Level1\\Level2\\IndexController::saveAction()

Attributes
----------

[](#attributes)

Croute optionally supports controller and action attributes. Two attributes are included out of the box, HttpMethod and Secure.

### HttpMethod

[](#httpmethod)

Restricts the allowed http methods. Returns a 400 response if the method does not match.

```
    #[HttpMethod('POST')]
    public function saveAction()
```

### Secure

[](#secure)

Requires a secure connection. If the connection is not https send a 301 redirect to the same url with the https protocol.

```
#[Secure]
class IndexController extends Controller
{
```

### Custom Attributes

[](#custom-attributes)

To create a custom attribute, implement the RoutingAttribute interface on your attribute, and an AttributeHandler.

```
#[\Attribute(\Attribute::TARGET_CLASS|\Attribute::TARGET_METHOD)]
class MyAttribute implements RoutingAttribute
{
    public function __construct(public string $option)
    {}
}
```

```
class MyAttributeHandler extends BasicAttributeHandler
{
    public function getAttributeClass(): string
    {
        return MyAttribute::class;
    }

    public function handleRequest(MyAttribute|RoutingAttribute $attribute, Request $request): ?Response
    {
        // Return a response will immediately return that response, bypassing the normal controller action
        if ($attribute->option == 'teapot') {
            return new Response("I'm a teapot", Response::HTTP_I_AM_A_TEAPOT);
        }
        return null;
    }
}
```

Add the attribute handler to the router, and your custom attribute will be ready to use.

```
$router->addAttributeHandler(new MyAttributeHandler());
```

Events
------

[](#events)

Symfony events are dispatched for every step in the routing process. A total of 12 events are dispatched in a successful request:

1. router.request
2. router.controller\_loaded
3. router.controller\_loaded.{ControllerName}
4. router.before\_action
5. router.before\_action.{ControllerName}
6. router.before\_action.{ControllerName}.{actionName}
7. router.after\_action
8. router.after\_action.{ControllerName}
9. router.after\_action.{ControllerName}.{actionName}
10. router.before\_response\_sent
11. router.response\_sent
12. router.response\_sent.{ControllerName}
13. router.response\_sent.{ControllerName}.{actionName}

The {ControllerName} will be sans 'Controller' and {actionName} sans 'Action' i.e IndexController::indexAction -&gt; router.before\_action.Index.index.

At any time before the response is sent, in an event listener you can set a response on the event to bypass the action and send instead.

```
    public function myListener(ControllerLoadedEvent $event)
    {
        $event->setResponse(new Response('PermissionDenied', 403));
    }
```

Error Handling
--------------

[](#error-handling)

Proper error handling is not really something that I can do for you. It's up to you to determine how to do logging, how and when to render a pretty error page. To handle errors, implement the EventHandlerInterface and set your error handler on the router. Your class will be called when common routing events occur (i.e. 404 errors) and when there is an exception during the routing process.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](CONTRIBUTING.md) for details.

###  Health Score

53

—

FairBetter than 97% of packages

Maintenance69

Regular maintenance activity

Popularity35

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity81

Battle-tested with a long release history

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~227 days

Recently: every ~373 days

Total

19

Last Release

160d ago

Major Versions

0.9-beta → 1.02014-11-05

1.5.1 → 2.02022-06-04

2.0.1 → 3.0.02024-11-05

PHP version history (5 changes)0.9-betaPHP &gt;=5.3.3

1.0PHP &gt;=5.4

1.4PHP &gt;=7.2

2.0PHP &gt;=8.0

3.0.0PHP &gt;=8.1

### Community

Maintainers

![](https://www.gravatar.com/avatar/bf016ae612f01684bc359174b8bb8db688a3de817457829ea83da6690df975f0?d=identicon)[thewunder](/maintainers/thewunder)

---

Top Contributors

[![thewunder](https://avatars.githubusercontent.com/u/1265740?v=4)](https://github.com/thewunder "thewunder (58 commits)")

---

Tags

routerrouting

###  Code Quality

TestsPHPUnit

Static AnalysisRector

### Embed Badge

![Health badge](/badges/thewunder-croute/health.svg)

```
[![Health](https://phpackages.com/badges/thewunder-croute/health.svg)](https://phpackages.com/packages/thewunder-croute)
```

###  Alternatives

[laravel/framework

The Laravel Framework.

34.7k509.9M17.0k](/packages/laravel-framework)[shopware/platform

The Shopware e-commerce core

3.3k1.5M3](/packages/shopware-platform)[drupal/core-recommended

Locked core dependencies; require this project INSTEAD OF drupal/core.

6939.5M343](/packages/drupal-core-recommended)[sulu/sulu

Core framework that implements the functionality of the Sulu content management system

1.3k1.3M152](/packages/sulu-sulu)[klein/klein

A lightning fast router for PHP

2.7k1.1M31](/packages/klein-klein)[contao/core-bundle

Contao Open Source CMS

1231.6M2.4k](/packages/contao-core-bundle)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
