Movatterモバイル変換


[0]ホーム

URL:


Skip to content
DEV Community
Log in Create account

DEV Community

Eivin Landa
Eivin Landa

Posted on

     

Laravel route binding for finite objects

Dependency injection in Laravel is a complicated topics and it's mostly used for 3rd party packages and some internals. You can utilise it in your own application too, but in my opinion it often complicates the code more than it's worth and makes debugging much harder.
There is one very good use for it, and one that you're probably already using. Route binding for eloquent models. Eg. if you have a model,Saw, the route could look something like this

<?phpuseIlluminate\Support\Facades\Route;useSaw\Http\Controllers\SawController;Route::get('/saw/{saw}',[SawController::class,'show'])->name('saw.show');
Enter fullscreen modeExit fullscreen mode

And then in the controller you can directly access the saw model in the show method like this

<?phpnamespaceSaw\Http\Controllers;useIlluminate\Contracts\View\View;useIlluminate\Http\Request;useIlluminate\Routing\Controller;useSaw\Models\Saw;classSawControllerextendsController{publicfunctionshow(Request$request,Saw$saw):View{returnview('saw.show',['saw'=>$saw]);}}
Enter fullscreen modeExit fullscreen mode

This is makes it super easy to create routes for eloquent models and gives you instant access to the model you want. In some cases you might have objects that has a finite set. In my case I have 2 saw machines and I don't want to store them in the database because they will always be the same and they each have some unique rules and code that runs for each individual machine. That means that making an eloquent model for the Saw model is a bad fit because I want to avoid tightly coupling code with the database, but I still want the ease of use for routing and be able to access the model directly based on it's id.
I took a look at how eloquent models get resolved during the routing process and found that all that's needed is to attach theUrlRoutable contract on our class and then Laravel will use reflection magic via middleware to inject the correct objects.

<?phpnamespaceSaw;useIlluminate\Contracts\Routing\UrlRoutable;useSaw\Enums\SawTypeEnum;useSaw\Repositories\SawRepository;classSawimplementsUrlRoutable{publicfunction__construct(public?int$id=null,public?SawTypeEnum$sawTypeEnum=null,){}publicfunctiongetRouteKey():?int{return$this->id;}publicfunctiongetRouteKeyName():string{return'id';}publicfunctionresolveRouteBinding($value,$field=null):?Saw{/** @var SawRepository $repository */$repository=app(SawRepository::class);return$repository->getById($value);}publicfunctionresolveChildRouteBinding($childType,$value,$field){// I'm not sure how this one works so I just return null// and it's not required for my applicationreturnnull;}}
Enter fullscreen modeExit fullscreen mode

UrlRoutable requires you to implement four methods,getRouteKey,getRouteKeyName,resolveRouteBinding andresolveChildRouteBinding.

  • getRouteKey should return the route key or id value of the object. This is usually the id or the slug of the object you have.
  • getRouteKeyName should return the name of the property that has the key value.
  • resolveRouteBinding takes a parameter, value, that is the id of the object to get and should return the object that gets injected.
  • resolveChildRouteBinding is related to child routing which I haven't looked into. If you know more then please comment and tell me.

Because I only have a couple of saws I made a quite basic repository class to house them.

<?phpnamespaceSaw\Repositories;useSaw\Saw;classSawRepository{privatearray$saws;publicfunctionaddSaw(Saw$saw):SawRepository{$this->saws[$saw->id]=$saw;return$this;}publicfunctiongetById(int$id):?Saw{return$this->saws[$id]??null;}}
Enter fullscreen modeExit fullscreen mode

To populate the repository I used Laravels singleton method to bind it to the application in mySawProvider class.

publicfunctionregister():void{$this->app->singleton(SawRepository::class,function(){$sawRepository=newSawRepository();$sawRepository->addSaw(newSaw(id:1,sawTypeEnum:SawTypeEnum::CASING));$sawRepository->addSaw(newSaw(id:2,sawTypeEnum:SawTypeEnum::MOULDING));return$sawRepository;});}
Enter fullscreen modeExit fullscreen mode

There are other ways to deal with finite objects in Laravel, but I quite like this route binding method as it lets me use my own custom objects and classes as part of the routes and have the correct objects injected into the controller methods.
I've seen many, many examples where developers have fallen for the temptation to put finite models that is directly connected with the code into the database as eloquent models and it has always resulted in headaches for several reasons. Testing becomes harder because you have to ensure that you seed the database before you can test. If you ever need to change the objects you have to first change it in the database and then you have to make sure that you also update the seeding code.
Whenever you have a finite set of objects that have specific rules or code that execute based on each individual object then I believe it's much better that these objects are solely governed by code and should not be coupled with the database at all.
Using a custom repository class andUrlRoutable for the model is a great way to achieve this.

Top comments(0)

Subscribe
pic
Create template

Templates let you quickly answer FAQs or store snippets for re-use.

Dismiss

Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment'spermalink.

For further actions, you may consider blocking this person and/orreporting abuse

Building web applications for automation with Laravel
  • Location
    Arendal, Norway
  • Work
    CEO at Cove AS
  • Joined

Trending onDEV CommunityHot

DEV Community

We're a place where coders share, stay up-to-date and grow their careers.

Log in Create account

[8]ページ先頭

©2009-2025 Movatter.jp