Weave Code
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

Object Routing Laravel Package

jms/object-routing

jms/object-routing is a PHP library for routing based on object state rather than URLs. Define routes and generate targets by evaluating objects and their metadata, enabling flexible navigation and link generation in domain-driven apps.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require jms/object-routing
    

    Add to composer.json under autoload:

    {
        "autoload": {
            "psr-4": {
                "App\\": "app/",
                "JMS\\": "vendor/jms/object-routing/"
            }
        }
    }
    

    Run composer dump-autoload.

  2. Basic Usage Define a route generator class (e.g., app/Generators/UserGenerator.php):

    use JMS\Router\Generator\GeneratorInterface;
    use JMS\Router\Generator\GeneratorContext;
    use JMS\Router\Generator\RouteGeneratorInterface;
    
    class UserGenerator implements RouteGeneratorInterface {
        public function generate(GeneratorContext $context) {
            $user = $context->getObject();
            return '/users/' . $user->getId();
        }
    }
    
  3. Register Generator Bind the generator in Laravel’s service container (e.g., in AppServiceProvider):

    $this->app->bind(RouteGeneratorInterface::class, function ($app) {
        return new UserGenerator();
    });
    
  4. Generate Routes Use the router in a controller or service:

    use JMS\Router\Router;
    use JMS\Router\Generator\RouteGeneratorInterface;
    
    public function show(User $user) {
        $router = new Router();
        $router->addGenerator('user', $this->app->make(RouteGeneratorInterface::class));
        $route = $router->generate('user', $user);
        return redirect($route);
    }
    

Implementation Patterns

Common Workflows

  1. Dynamic Route Generation Useful for RESTful APIs or admin panels where routes depend on object properties (e.g., /posts/{id}/comments/{commentId}). Example:

    class PostCommentGenerator implements RouteGeneratorInterface {
        public function generate(GeneratorContext $context) {
            $post = $context->getObject('post');
            $comment = $context->getObject('comment');
            return "/posts/{$post->getId()}/comments/{$comment->getId()}";
        }
    }
    
  2. Contextual Routing Pass additional context (e.g., locale, tenant) via GeneratorContext:

    $context = new GeneratorContext($object, ['locale' => 'en']);
    $router->generate('route_name', $object, $context);
    
  3. Integration with Laravel’s Router Combine with Laravel’s Route::get() for hybrid routing:

    Route::get('/dynamic/{id}', function ($id) {
        $user = User::find($id);
        $router = app(Router::class);
        return $router->generate('user_profile', $user);
    });
    
  4. Caching Routes Cache generated routes to avoid regeneration (e.g., in a service):

    public function getCachedRoute($object, $generatorName) {
        $cacheKey = md5($generatorName . serialize($object));
        return Cache::remember($cacheKey, now()->addHours(1), function () use ($object, $generatorName) {
            return $router->generate($generatorName, $object);
        });
    }
    
  5. Validation Before Generation Validate objects before generating routes (e.g., ensure id exists):

    public function generate(GeneratorContext $context) {
        $user = $context->getObject();
        if (!$user->getId()) {
            throw new \InvalidArgumentException('User ID is required.');
        }
        return "/users/{$user->getId()}";
    }
    

Gotchas and Tips

Pitfalls

  1. Outdated Package

    • Last release in 2016; test thoroughly for Laravel 5.8+ compatibility (may require polyfills or forks).
    • Example polyfill for GeneratorContext:
      use JMS\Router\Generator\GeneratorContext as BaseContext;
      class GeneratorContext extends BaseContext {
          public function __construct($object, array $parameters = []) {
              parent::__construct($object, $parameters);
          }
      }
      
  2. No Built-in Laravel Integration

    • Requires manual binding to Laravel’s container. Avoid global state; prefer dependency injection.
    • Example DI in controllers:
      public function __construct(private Router $router) {}
      
  3. Context Cloning Issues

    • GeneratorContext may not clone objects properly. Use unserialize() or clone objects explicitly:
      $context = new GeneratorContext(clone $object, $parameters);
      
  4. Route Collisions

    • Ensure generator names are unique (e.g., user_profile vs. user_edit). Use namespaces:
      $router->addGenerator('user.profile', $generator);
      
  5. Performance with Complex Objects

    • Generating routes for deeply nested objects (e.g., User->Posts->Comments) can be slow. Cache or lazy-load.

Debugging Tips

  1. Inspect Context Dump GeneratorContext to verify objects/parameters:

    $context = new GeneratorContext($user, ['tenant' => 'acme']);
    dd($context->getObject(), $context->getParameters());
    
  2. Test Edge Cases

    • Null objects: if (!$context->getObject()) throw new \RuntimeException('Object missing.');
    • Missing properties: Use method_exists() or isset() checks.
  3. Logging Generators Log generated routes for debugging:

    public function generate(GeneratorContext $context) {
        $route = "/users/{$context->getObject()->getId()}";
        \Log::debug("Generated route: {$route}", ['object' => $context->getObject()]);
        return $route;
    }
    

Extension Points

  1. Custom Generators Extend RouteGeneratorInterface for domain-specific logic (e.g., API versioning):

    class ApiV1UserGenerator implements RouteGeneratorInterface {
        public function generate(GeneratorContext $context) {
            return "/api/v1/users/{$context->getObject()->getId()}";
        }
    }
    
  2. Middleware for Route Generation Create middleware to generate routes before dispatching:

    public function handle($request, Closure $next) {
        $request->merge(['route' => $this->router->generate('dynamic_route', $request->user)]);
        return $next($request);
    }
    
  3. Reverse Routing Combine with Laravel’s route() helper for bidirectional routing:

    // Forward: Object → Route
    $route = $router->generate('user', $user);
    
    // Reverse: Route → Object (manual lookup)
    $user = User::where('id', request('id'))->first();
    
  4. Dynamic Route Parameters Support optional parameters in generators:

    public function generate(GeneratorContext $context) {
        $user = $context->getObject();
        $params = $context->getParameters();
        return "/users/{$user->getId()}" .
               ($params['action'] ?? null ? "/{$params['action']}" : '');
    }
    
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.
croct/coding-standard
croct/plug-php
nqxcode/phpmorphy
boundwize/pyrameter
testo/facade
headercat/phpstan-extension-ide-helper
yosymfony/parser-utils
innmind/black-box
babenkoivan/elastic-migrations
babenkoivan/elastic-adapter
develia/commons
dmstr/symfony-system-resources-bundle
cuci/prototurk-sdk
cuci/prototurk-sdk-symfony
renatomarinho/laravel-page-speed
develia/geo-bundle
austinheap/laravel-database-encryption
dreamzy/livewire-charts
touchestate-sdk/php-sdk
22h/doctrine-garbage-collection-bundle