PHPackages                             haikara/flat-route - 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. [Utility &amp; Helpers](/categories/utility)
4. /
5. haikara/flat-route

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

haikara/flat-route
==================

0.1.0(1y ago)07PHPPHP &gt;=8.0 &lt;8.4.0

Since Aug 20Pushed 1y ago1 watchersCompare

[ Source](https://github.com/HaikaraSakura/flat-route)[ Packagist](https://packagist.org/packages/haikara/flat-route)[ RSS](/packages/haikara-flat-route/feed)WikiDiscussions main Synced today

READMEChangelog (1)Dependencies (6)Versions (2)Used By (0)

FlatRoute
=========

[](#flatroute)

セットアップ
------

[](#セットアップ)

```
composer require knp/flat-route
```

ContainerInterfaceの実装が必要なので、任意のライブラリを用意する。
下記の例ではknp/dineryを使用する。

```
// ContainerInterfaceの実装を用意
$container = new Knp\Dinery\Container();

// Routerクラスをインスタンス化
$router = new Knp\FlatRoute\Router($container);

// サブディレクトリ運用の場合、ベースになるURIを設定する
$router->setBaseRoute('/knp');
```

ルーティング設定
--------

[](#ルーティング設定)

### 基本的なルーティング

[](#基本的なルーティング)

PSR-7の実装が必要。下記の例ではlaminas/laminas-diactorosを利用する。

Router::get/Router::postの第一引数にパスを指定し、第二引数に実行したい処理を渡す。
パスのことをルーティングパターン、実行したい処理のことをルーティングコールバックという。

```
$response = new Laminas\Diactoros\Response;

$router->get('/', function ($request, $args) use ($response) {
    $response->getBody()->write('トップページ');
    return $response;
}),

$router->get('/products/create', function ($request, $args) use ($response) {
    $response->getBody()->write('製品登録画面');
    return $response;
}),

$router->post('/products/store', function ($request, $args) use ($response) {
    $response->getBody()->write('製品登録処理');
    return $response;
});

// RouterにRequestを渡して実行
$request = Laminas\Diactoros\ServerRequestFactory::fromGlobals();
$response = $router->handle($request);

// Responseを出力
(new \Knp\FlatRoute\Emitter\ResponseEmitter($response))->payout();
```

ルーティングコールバックとDIコンテナ
-------------------

[](#ルーティングコールバックとdiコンテナ)

ルーティングコールバックにはクラスの完全修飾名を渡すこともできる。
クラス名はcallable値ではないが、Containerによって自動的にインスタンス化される。

```
$router->get('/', TopAction::class);
```

- `__invoke`を実装していること
- `__invoke`の引数が$request, $argsであること
- `__invoke`の返り値が`ResponseInterface`であること

インスタンス化してオブジェクトをコールバックとして渡すこともできるが、
そうするとすべてのActionクラスが事前にインスタンス化されてしまうので効率が悪い。
完全修飾名を渡す方式であれば、該当のルートのActionのみがインスタンス化される。

パラメータのフィルタリングとバリデーション
---------------------

[](#パラメータのフィルタリングとバリデーション)

ruleメソッドを用いて、ルーティングパラメータの値をフィルタリングし、
特定の値のみ受け付けるよう制限を加えることが可能。やりすぎ注意。

```
// year => 2000年以降
// month => 1月から12月
$router->get('/column/:year/:month', ColumnIndexAction::class)
    ->rule('year', Rules::integer()->min(2000))
    ->rule('month', Rules::integer()->range(1, 12));

// user_id => 英数字、10ケタ
$router->get('/profile/:user_id', UserProfileInexAction::class)
    ->rule('user_id', Rules::alnum()->length(10));

// customer_code => 数字のみ、8ケタ（0埋めありの文字列を想定）
$router->get('/customers/:customer_code/edit', CustomersEditAction::class)
    ->rule('customer_code', Rules::digit()->length(8));

// filename =>拡張子が 'jpg', 'png', 'webp'のいずれか
$router->get('/products/images/:filename', ProductsImageAction::class)
    ->rule('filename', Rules::file()->ext('jpg', 'png', 'webp'));
```

ミドルウェア
------

[](#ミドルウェア)

ルーティングと各ルートにはMiddlewareを追加することができる。
Middlewareのオブジェクトか完全修飾名を渡すこと。

- あとから追加したMiddlewareのほうが外側で実行される＝最後に追加したMiddlewareが一番はじめに実行される。
- ルーティングに追加されたMiddlewareは、全ルートに適用される。
- ルーティングに追加されたMiddlewareは、各ルートが持つMiddlewareより常に外側で実行される。
- ルーティングコールバックが一番内側で実行される。

```
class Middleware1 implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
        echo '1';
        $response = $handler->handle($request);
        echo '1';
        return $response;
    }
}

class Middleware2 implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
        echo '2';
        $response = $handler->handle($request);
        echo '2';
        return $response;
    }
}

class Middleware3 implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
        echo '3';
        $response = $handler->handle($request);
        echo '3';
        return $response;
    }
}

class Middleware4 implements MiddlewareInterface {
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface {
        echo '4';
        $response = $handler->handle($request);
        echo '4';
        return $response;
    }
}

// ルートにMiddlewareを追加
$router->get('/main_action', function ($request, $args) use ($response) {
    echo ' Action ';
    return $response;
})
->addMiddleware(Middleware1::class)
->addMiddleware(Middleware2::class);

// ルーティング全体にMiddlewareを追加
$router->addMiddleware(Middleware3::class);
$router->addMiddleware(Middleware4::class);

// 出力される内容
// 4321 Action 1234
```

オプショナルパターン
----------

[](#オプショナルパターン)

ノードが増減するルーティングパターンに同じActionを設定する場合、
下記のようにすべてのパターンを別個に設定することもできるが、
特にバリデーションやMiddlewareの設定を伴う場合に、記述が冗長になりやすい。

```
// 全記事
$router->get('/column', ColumnIndexAction::class)
    ->addMiddleware(Middleware1::class);

// 特定の年の記事
$router->get('/column/:year', ColumnIndexAction::class)
    ->rule('year', Rules::integer()->min(2000))
    ->addMiddleware(Middleware1::class);

// 特定の年月の記事
$router->get('/column/:year/:month', ColumnIndexAction::class)
    ->rule('year', Rules::integer()->min(2000))
    ->rule('month', Rules::integer()->range(1, 12))
    ->addMiddleware(Middleware1::class);

// こんなのやってられない！
```

あってもなくてもいい部分を\[\]で囲むと一括で設定することができる。

```
$router->get('/column[/:year][/:month]', ColumnIndexAction::class)
    ->rule('year', Rules::integer()->min(2000))
    ->rule('month', Rules::integer()->range(1, 12))
    ->addMiddleware(Middleware1::class);
```

ルートネームとパスの生成
------------

[](#ルートネームとパスの生成)

ルートに名前を付けることで、そのルートのパスを別のActionで簡単に組み立てられるようになる。

```
$router->get('/column[/:year][/:month]', ColumnIndexAction::class)
    ->rule('year', Rules::integer()->min(2000))
    ->rule('month', Rules::integer()->range(1, 12))
    ->setName('ColumnIndex'); // Route::setNameでルート名を設定

// 別のルートのActionにて、ルート名を指定して NamedRoutePatterns::getRoutePathを呼ぶと、
// パラメータが割り当てられたパスの文字列を取得できる。
$router->get('/products/:product_id', function ($request, $args) use ($response) {
    $path = NamedRoutePatterns::getRoutePath(
        $request,
        'ColumnIndex',
        ['year' => 2023, 'month' => 1]
    );
     // '/column/2023/1'が得られる

    return $response;
});
```

ルートグループ
-------

[](#ルートグループ)

ルートをグループ化し、Middlewareを一括で登録することができる。

```
// 通常のルーティング
$router->get('/admin/login', LoginAction::class);

// グループ化されたルーティング
$router
    ->group('/admin', function (RouteGroup $router) {
        $router->get('/products', ProductsIndexAction::class);
        $router->get('/customers', CustomersIndexAction::class);
    })
    ->addMiddleware(AuthMiddleware::class);
```

上記の例では`/admin/products`と`/admin/customers`に一括で`AuthMiddleware`が適用される。
`/admin/login`も`/admin`配下のルートだが、グループには含まれていないので`AuthMiddleware`の適用外となる。

グループはネスト可能。

リクエストメソッドによってActionを分ける
-----------------------

[](#リクエストメソッドによってactionを分ける)

同じルートパターンで異なるリクエストメソッドに別々のActionをセットできる。
通常のフォームではGETとPOSTしかないが、REST APIの設計で活用できる。

```
// ユーザー一覧画面
$router->get('/users', UsersIndexAction::class);

// ユーザー登録画面
$router->get('/users/create', UsersCreateAction::class);

// ユーザー登録処理
$router->post('/users', UsersIndexAction::class);

// ユーザー情報編集画面
$router->get('/users/:id',  UsersEditAction::class);

// ユーザー情報編集画面
$router->patch('/users/:id',  UsersUpdateAction::class);

// ユーザー削除処理
$router->delete('/users/:id',  UsersUpdateAction::class);
```

###  Health Score

24

—

LowBetter than 31% of packages

Maintenance32

Infrequent updates — may be unmaintained

Popularity4

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity47

Maturing project, gaining track record

 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

Unknown

Total

1

Last Release

681d ago

### Community

Maintainers

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

---

Top Contributors

[![t-mori-haikara](https://avatars.githubusercontent.com/u/87011031?v=4)](https://github.com/t-mori-haikara "t-mori-haikara (1 commits)")

### Embed Badge

![Health badge](/badges/haikara-flat-route/health.svg)

```
[![Health](https://phpackages.com/badges/haikara-flat-route/health.svg)](https://phpackages.com/packages/haikara-flat-route)
```

###  Alternatives

[cakephp/cakephp

The CakePHP framework

8.9k19.5M1.8k](/packages/cakephp-cakephp)[typo3/cms

TYPO3 CMS is a free open source Content Management Framework initially created by Kasper Skaarhoj and licensed under GNU/GPL.

1.2k1.9M122](/packages/typo3-cms)[mcp/sdk

Model Context Protocol SDK for Client and Server applications in PHP

1.5k1.5M85](/packages/mcp-sdk)[bref/bref

Bref is a framework to write and deploy serverless PHP applications on AWS Lambda.

3.4k10.6M67](/packages/bref-bref)[typo3/cms-core

TYPO3 CMS Core

3713.2M5.1k](/packages/typo3-cms-core)[xima/xima-typo3-frontend-edit

Frontend Edit - This extension provides an edit button for editors within frontend content elements.

1414.3k](/packages/xima-xima-typo3-frontend-edit)

PHPackages © 2026

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