PHPackages                             baraja-core/smart-router - 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. [Database &amp; ORM](/categories/database)
4. /
5. baraja-core/smart-router

AbandonedArchivedLibrary[Database &amp; ORM](/categories/database)

baraja-core/smart-router
========================

v2.0.0(5y ago)116.3k2PHPPHP ^8.0

Since Sep 25Pushed 4y ago1 watchersCompare

[ Source](https://github.com/baraja-core/smart-router)[ Packagist](https://packagist.org/packages/baraja-core/smart-router)[ Docs](https://github.com/baraja-core/smart-router)[ RSS](/packages/baraja-core-smart-router/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (8)Dependencies (9)Versions (12)Used By (2)

Smart router
============

[](#smart-router)

[![Integrity check](https://github.com/baraja-core/smart-router/workflows/Integrity%20check/badge.svg)](https://github.com/baraja-core/smart-router/workflows/Integrity%20check/badge.svg)

A router is a component for bidirectional translation between a URL and an application request. By bidirectional we mean the possibility to derive a presenter action from a URL, but also vice versa, to generate a corresponding URL to the action.

The package provides a default implementation of `SmartRouter`, which improves the default routing method in Nette and adds the ability to store specific URLs in a database (or other repository), including their parameters, language, and advanced configuration.

Installation
------------

[](#installation)

The package is part of the default [Baraja Sandbox](https://github.com/baraja-core/sandbox).

Or you can install manually via Composer:

```
$ composer require baraja-core/smart-router

```

All routing rules are defined in the `RouterFactory` class, where we can inject the `SmartRouter` service like this:

```
public static function createRouter(SmartRouter $smartRouter): RouteList
{
    $router = new RouteList;

    // Register SmartRouter
    $router[] = $smartRouter;

    // Optionally add additional routes or a collection of routes
    $router[] = self::createFrontRouter();

    return $router;
}
```

We will ensure that all requests are first processed via SmartRouter and only in case of failure will other regular routes be used.

SmartRouter
-----------

[](#smartrouter)

`SmartRouter` is my internal implementation of how routing should work. The entire request routing process works fully automatically, and can be influenced by a very detailed configuration, which is then cached.

We divide routing into 3 separate parts:

- `Match`: Rewrite URL to application request (request processing)
- `Construct URL`: Create a URL based on an application request
- `Rewriter`: Implementation of an interface for rewriting parameters on the URL part, where most of the magic happens

The default implementation of the Rewriter is `DoctrineRewriter` ([more information](https://github.com/baraja-core/doctrine-router)), which routes URLs based on a database table. Its internal implementation is extremely effective.

For smaller applications or in the case of testing, you can use `StaticRewriter`, which performs rewriting based on a physically stored in array.

Match - Accept the request URL
------------------------------

[](#match---accept-the-request-url)

The following text describes how the list of found parameters is compiled according to the loaded URL.

Routing is divided into 4 logical steps.

1. Find the required URL in the cache. If the record exists (it can also be negative), we route it directly and we don't have to search further
2. Preparation of the cache for configuration, if any, we will use from the cache,
3. Finding the current URL (routing) according to the internal logic (will be described below),
4. Save the routed parameters to the key-value cache, which will be used next in the first step.

The request cache contains 2 parameters:

- Expiration by constant `CACHE_EXPIRATION` (default 30 minutes)
- Tag with value `route/:`

> **Caution:** Special behavior
>
> All requests that we can handle are still being processed internally in the router, which always adds the `locale` key. If not specified during routing, we return the default language for the current site. If the default language does not exist, we return English.
>
> If the current language of the matched request does not exist, we throw an `E_NOTICE` level error.

**Sending and processing the matched application request**

Whether we find the application request in the cache or it is created by a direct match, it will always be sent by the `returnRequest()` method.

The task of this method is to set the current environment (private property `environment`) to the internal state of the router, which will be used for routing other requests and compiling URLs. The currently matched environment will only be used if it is better than the internally set one.

The environment priority rating table is stored in the `environmentScoreTable` configuration key and in the basic implementation is:

- `localhost`: 1
- `beta`: 2
- `production`: 3

At the same time, the task of this method is to set the language to the Translator.

> **Attention:** If no request has been routed, it is not possible to reliably determine the language and environment during further processing of the application and generation of links.
>
> If we generate a link to an e-mail in CLI mode (cron or another background task), for example, it is always necessary to insert the language (`locale`) and environment (`environment`) into all requests. If we do not enter these values, the router may behave differently than we expect.

**Entity `MatchRequest` - Internal logic of request processing**

The `MatchRequest` entity serves as a helper to process the current URL and return results. The instance is created by the Smart router itself.

Final processing is done only after calling a single public method `match()`, which returns a parameter field in case of success, or `null` in case of error or invalid request.

The internal logic of processing can change (and improve) over time, this text describes only general principles. A description of the specific implementation and an explanation is available directly in the implementation as a comment.

Processing procedure:

1. Finding a route (`processRoute()` method)

Currently we only support `Front` and `Admin` modules, we are looking for matching `presenter` and `action`.

We gradually try the rules:

- Is the Homepage or an empty URL? (`$slug === ''`)
- Is there an admin request? If so, we route regularly according to the mask `admin/[/]/`
- Transcription based on `Rewriter` + addition of parameters, environment and language.
- A regular expression (corresponds to the ` / ` mask) for backward compatibility of old or `lazy` URLs.

2. We will process the language of the request

The resulting language of the request is very difficult to determine, because when designing the routing kernel, we came across dozens of special cases where it is not \*\* easy \*\* to decide. It is usually a combination of domain language vs. another language slugu, or locale parameter.

The solution consists in accumulating all available languages ​​that we have available about the current URL, sorting them into fields according to keys and then selecting the best one according to priorities.

We distinguish 3 basic priority levels:

- *(best)* `URL parameter`: Contained in `?locale=en`,
- `Path / Slug`: Part of the URL is assigned to a specific language according to the rewrite,
- `Domain`: The language is typical for the currently routed domain.

3. Compilation of final parameters

In this step, the last check and purge of the parameters will be performed, which will be sent as an application request.

The minimum configuration always contains values:

- `presenter` (in the form `:`)
- `action`
- `locale` (string)
- `environment` (string, values: `localhost`, `beta`, `production`)

Construct URL - Build a URL
---------------------------

[](#construct-url---build-a-url)

The following text describes how the URL is generated according to the specified parameters.

Before generating the URL itself, it is necessary to verify the existence of basic keys, according to which we will determine the type of URL.

It's about:

- `locale`: The language in which the URL is available,
- `environment`: The environment where the URL leads (for example, to avoid generating a link to `production` or other combinations on `beta`).

1. We find the URL in the cache according to the key composed of parameters,
2. If the cache does not contain the resulting URL, we will prepare the configuration, or read it from the cache,
3. Build the required URL based on the internal logic (described below),
4. Write to the cache and return the final URL, or `null` if it is not possible to crash.

The process of compiling a URL is much more challenging to match and must take into account more rules. However, some parts work the same.

The basis of a correctly generated URL is its uniqueness, even in the future. It must not contain logical disputes (for example, the slug language does not fit the domain language), so extremely complex logic and a set of rules are used for assembly.

Before building the final URL, an instance of the `ConstructUrlRequest` entity is created, which requires `(array $params, Rewriter $rewriter, array $config = null)` and sets the internal state of the entity for further generation based on the configuration.

When compiling, we find out the following values:

- `environment`: The environment in which we will generate the URL (different for localhost or domain production, for example),
- `locale`: URL language
- `lazy`: A `bool` flag indicating a simply assembled regular URL without using `Rewriter`, which can slow down - explained below,
- `presenter` and `action` for page type context.

The assembly itself is performed only when the `construct()` method is called, which returns `string` with an absolute URL or `null` in the event of an error.

The procedure again has many steps:

1. Obtaining a domain

- Is the environment empty, unknown, or has no default domain defined for it in the configuration? Then the current domain is retained.
- If the environment exists, we will find the best domain for the desired language,
- If the domain for the required language does not exist, we return the default domain for the environment and remember the `needLocaleParameter` flag, which says that we must pass the language in a parameter in the URL.

Before returning the domain, we check the configuration to see if we should add `www.` before the domain (`useWww` flag).

2. Processing `path` (`slug`)

Now it depends on whether we are building the path according to real parameters (using the `Rewriter` interface), or it is a `lazy link`, ie a simplified version.

Lazy link generates a path in the form `/`, generating only `/` for `Homepage:default`, only `/product` for `Product:default` and so on.

As for the real link, we generate the URL from `Rewriter` using the `rewriteByParameters()` method, while the router's internal logic performs further cleanup, such as comparing languages ​​and removing overwritten parameters. More info in the section on the transcriber.

3. We will compile the final URL according to the general format:

`:///?`

Lazy URL - Simplified URL format
--------------------------------

[](#lazy-url---simplified-url-format)

The Smart Router supports the so-called `lazy URL`, which is a permanent URL generated using regular expressions, which does not require access to the `Rewriter` or the database during compilation and parsing.

Its advantage is extremely fast reading and creation. It is especially suitable for large listings of items (such as products in a catalog), where building a \* nice URL \* would take an unnecessarily long time and completely delay loading the page.

Lazy URLs are generated during generation by passing the value `['lazy' => true]`.

Rewriter
--------

[](#rewriter)

In order to be able to dynamically rewrite the URL to the application request (parameters) and back (generate the URL), it was necessary to implement a `Smart router`, which provides a general algorithm for this task.

In practice, however, it is necessary for different clients to rewrite URLs in different ways - but mostly from a database. The `Rewriter` interface is used for this task, which is good to know especially in a situation where we need to change the method of compiling URLs, or rewrite from a static file (small websites or test progress).

**`rewriteByPath(string $path):?array;`**

Overwrites the current path (`slug`) in the parameter field. If not, it returns `null`.

Minimum configuration to return:

```
[
   'presenter' => 'Front:Homepage',
   'action' => 'default',
   'locale' => 'en',
] + other parameters

```

**`rewriteByParameters interface (array $parameters):?RewriterParametersMatch;`**

Overwrites the required parameters on Slug and other properties. Returns the result as a type entity.

The task of the `RewriterParametersMatch` entity is to carry strict information about which `path` (`slug`) the URL was rewritten to, in which language and what parameters were used.

Example:

When routing the `/wheels` URL, a rewrite was performed on `Front:Category:detail` with the parameter `id = 1`.

We have to pass this parameter separately in the field, because the router overwrites the parameter `id = 1` into the slug `/kola`, which clearly represents this ID. Removal is also necessary so that the parameter is not further preserved in the URL, because it is already passed as part of the slug (inside the DB) and can therefore always be re-routed.

📄 License
---------

[](#-license)

`baraja-core/smart-router` is licensed under the MIT license. See the [LICENSE](https://github.com/baraja-core/smart-router/blob/master/LICENSE) file for more details.

###  Health Score

33

—

LowBetter than 74% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity21

Limited adoption so far

Community13

Small or concentrated contributor base

Maturity65

Established project with proven stability

 Bus Factor1

Top contributor holds 93.5% 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 ~19 days

Recently: every ~26 days

Total

8

Last Release

1913d ago

Major Versions

v1.2.0 → v2.0.02021-02-11

PHP version history (4 changes)v1.0.0PHP &gt;=7.1.0

v1.1.0PHP &gt;=7.4.0

v1.2.0PHP ^7.4 || ^8.0

v2.0.0PHP ^8.0

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/3382204?v=4)[baraja](/maintainers/baraja)[@baraja](https://github.com/baraja)

---

Top Contributors

[![janbarasek](https://avatars.githubusercontent.com/u/4738758?v=4)](https://github.com/janbarasek "janbarasek (29 commits)")[![dependabot-preview[bot]](https://avatars.githubusercontent.com/in/2141?v=4)](https://github.com/dependabot-preview[bot] "dependabot-preview[bot] (2 commits)")

---

Tags

databasedomain-languageinternallanguageregular-routesrewrite-urlsrouter

###  Code Quality

Static AnalysisPHPStan

Type Coverage Yes

### Embed Badge

![Health badge](/badges/baraja-core-smart-router/health.svg)

```
[![Health](https://phpackages.com/badges/baraja-core-smart-router/health.svg)](https://phpackages.com/packages/baraja-core-smart-router)
```

###  Alternatives

[nette/database

💾 Nette Database: layer with a familiar PDO-like API but much more powerful. Building queries, advanced joins, drivers for MySQL, PostgreSQL, SQLite, MS SQL Server and Oracle.

5656.7M231](/packages/nette-database)[ublaboo/datagrid

DataGrid for Nette Framework: filtering, sorting, pagination, tree view, table view, translator, etc

2971.9M23](/packages/ublaboo-datagrid)[nextras/orm

Nextras Orm framework

3141.2M42](/packages/nextras-orm)[tomaj/nette-api

Nette api

36261.8k4](/packages/tomaj-nette-api)[kdyby/doctrine-cache

Doctrine Cache bridge for Nette Framework

101.3M19](/packages/kdyby-doctrine-cache)[baraja-core/doctrine

Doctrine port to Nette 3.0 with maximal performance.

13276.7k23](/packages/baraja-core-doctrine)

PHPackages © 2026

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