VOOZH about

URL: https://deepwiki.com/hypervel/router/4.2-model-binding-and-urlroutable

⇱ Model Binding and UrlRoutable | hypervel/router | DeepWiki


Loading...
Menu

Model Binding and UrlRoutable

Purpose and Scope

This document describes how to customize route parameter binding by implementing the UrlRoutable contract and registering explicit or model bindings with the Router. These mechanisms allow you to automatically resolve route parameters like {user} into rich objects (models, DTOs, enums) before they reach your controller.

For information about how the SubstituteBindings middleware orchestrates the overall parameter resolution process, see Route Parameter Binding. For general middleware configuration, see Middleware Configuration and Exclusions.


Binding Types Overview

The routing system supports three types of custom parameter binding, evaluated in the following priority order:

PriorityBinding TypeRegistration MethodUse Case
1Explicit BindingsRouter::bind()Custom resolution logic via closure
2Model BindingsRouter::model()Map parameter name to specific model class
3Type-based ResolutionAutomaticUse parameter type hint (UrlRoutable, Model, BackedEnum)

Sources: src/Middleware/SubstituteBindings.php78-96


The UrlRoutable Contract

Interface Definition

The UrlRoutable contract defines three methods for custom route binding behavior:


Method Responsibilities:

MethodReturn TypePurpose
getRouteKey()stringReturns the value to use in URLs (e.g., model's primary key or slug)
getRouteKeyName()stringReturns the database column name for route key lookup (e.g., "id", "slug")
resolveRouteBinding($value)Model|nullRetrieves the entity from storage using the route parameter value

Sources: src/Contracts/UrlRoutable.php9-32

Resolution Process


When SubstituteBindings encounters a parameter with a UrlRoutable type hint, it:

  1. Instantiates the class using make() (cached per class in $resolvedUrlRoutables)
  2. Calls resolveRouteBinding($routeKey) with the parameter value
  3. Throws UrlRoutableNotFoundException if the method returns null

Sources: src/Middleware/SubstituteBindings.php122-137 src/Exceptions/UrlRoutableNotFoundException.php9-18

Implementation Example

A typical UrlRoutable implementation delegates to model query logic:


This allows routes like /teams/{team} to automatically resolve {team} to a Team instance by slug, while also enforcing business logic (e.g., only active teams).

Sources: src/Contracts/UrlRoutable.php9-32 src/Middleware/SubstituteBindings.php126-137


Model Bindings

Registration

Model bindings map a parameter name to a specific model class, overriding type hints:


This binds the parameter name account to the Account model class. When a route parameter {account} appears in any route, it will always resolve to an Account instance, even if the controller type hint differs.

Sources: src/Router.php102-115

Storage and Retrieval


Model bindings are stored in the $modelBindings array property:

Validation

The Router::model() method validates:

  1. The class exists via class_exists()
  2. The class extends Hyperf\Database\Model\Model

If validation fails, a RuntimeException is thrown.

Sources: src/Router.php104-115

Resolution Behavior

When a model binding exists for a parameter:


The resolution process:

  1. Calls getRouteKeyName() on a new model instance to determine the query column
  2. Executes Model::where($columnName, $routeKey)->firstOrFail()
  3. Throws ModelNotFoundException if no record matches

Sources: src/Middleware/SubstituteBindings.php139-147


Explicit Bindings

Registration

Explicit bindings provide maximum flexibility by accepting a closure for custom resolution logic:


Sources: src/Router.php117-123

Storage and Priority


Explicit bindings are checked first, before model bindings or type hints. This gives them the highest priority in the resolution hierarchy.

Sources: src/Router.php32-36 src/Router.php117-123 src/Middleware/SubstituteBindings.php86-89


Resolution Strategy and Priority

Complete Resolution Flow


Sources: src/Middleware/SubstituteBindings.php78-120

Decision Table

ScenarioExplicit BindingModel BindingType HintResolution Method
1✓ Exists--Execute explicit binding closure
2✓ Exists-Query model using getRouteKeyName()
3UrlRoutableCall resolveRouteBinding() on instance
4ModelQuery model using getRouteKeyName()
5BackedEnumCall BackedEnum::tryFrom()
6OtherNo binding (pass original string)

Sources: src/Middleware/SubstituteBindings.php78-120

Code Entity Mapping


Sources: src/Router.php102-139 src/Middleware/SubstituteBindings.php78-162


Exception Handling

UrlRoutableNotFoundException

Thrown when a UrlRoutable implementation's resolveRouteBinding() method returns null:

Exception Structure:

  • Class: Hypervel\Router\Exceptions\UrlRoutableNotFoundException
  • Parent: RuntimeException
  • Message Format: "No query results for url routable [{class}] {routeKey}."

Thrown from: src/Middleware/SubstituteBindings.php131-133

Sources: src/Exceptions/UrlRoutableNotFoundException.php9-18

ModelNotFoundException

Thrown when model resolution fails (standard Hyperf exception from firstOrFail()):

Triggered by:

BackedEnumCaseNotFoundException

Thrown when enum resolution fails (from BackedEnum::tryFrom() returning null):

Triggered by: src/Middleware/SubstituteBindings.php153-159

Sources: src/Middleware/SubstituteBindings.php98-101


Practical Examples

Example 1: Custom UrlRoutable with Business Logic


Route usage:


Sources: src/Contracts/UrlRoutable.php9-32

Example 2: Explicit Binding for Conditional Resolution


Sources: src/Router.php117-123

Example 3: Model Binding Override


Sources: src/Router.php102-115


Summary

The model binding system provides three layers of customization:

  1. Explicit Bindings (highest priority): Full control via closures for complex resolution logic
  2. Model Bindings: Map parameter names to specific model classes
  3. UrlRoutable Interface: Implement custom resolution logic within the model itself

All three mechanisms integrate seamlessly with the SubstituteBindings middleware, which automatically resolves parameters before controller execution.

Sources: src/Router.php24-139 src/Middleware/SubstituteBindings.php26-163 src/Contracts/UrlRoutable.php9-32