Exploring magical Model injection in FilamentPHP
Hi everyone,
Everyhing is fine, but I wondered if there are any experts on Filament's DI I could quiz, because ever since learning about the magical DI available to us, I became completely consumed with the idea of never passing anything to a method ever again π
To help me understand a bit more about how the magic actually works though, here's an issue I'm running into: trying to get a Service class to DI the current instance of the Model. Take the following code as an example:
In my EnvironmentResource, inside an Infolist...
and the Service...
and the ServiceProvider...
Now, as I said, everything is working fine, in the Action, DI is injecting the current Environment model just fine, and it's injecting the Service as well, BUT... the Environment model that the Service class attempts to inject, it's a blank model.
Clearly the magic that is enabling the current instance of the Environment model to be injected (I presume it's Route Model Binding?) doesn't apply when a thing is calling a thing, rather than the thing being called directly. Obviously, I can work around this, and just pass in the Model as an argument, but... well, I was hoping someone could explain why it's not working in a little more detail, so I can both understand Laravel's DI better, but also so I can try and magic up a solution!
Solution:Jump to solution
In your case it should be
```php
$service = app(EnvironmentServiceInterface::class, ['environment' =>
$record]);...
8 Replies
I am confused, because you aren't using your
$environment_service
. Filament's DI is basically calling Laravel DI container with some context aware defaults like $record
, $livewire
, $action
, ...I removed the code to use it just to clean things up, but if you dd() on it, it's a perfectly instanced version of the EnvironmentServices class, and it HAS an Environment model attached, it's just an empty one - not the current model I'm viewing at the time.
I even tried dumping out $request over in the Service class, and it's showing Livewire paths, basically. I considered using the mount() method somewhere (not available in a Resource class though?), because according to Livewire's docs, that's the only place where you're going to get a decent shot at the $request path being a real one.
I think the issue is, that Laravel DI will create a new model, since it isn't aware of the currently injected
$record
. You need to resolve this yourself.
Something like this:
Hrm, tried that just now, and it didn't work. Tried '''PHP ['id' => $record->id]''' as well, no go. I guess, however, that passing the current record to the app facade isn't really any different to passing it to a method - I guess if there's no way to trick Laravel's DI into Route Model Binding off the original request URL, then I'm pretty much stuck with having to pass something to something.
I know I am trying to push the magic too far, but the idea of never passing arguments to methods ever again is just too tempting!
I guess, however, that passing the current record to the app facade isn't really any different to passing it to a methodI think it is. The latter explicitly passes a
$record
instance for that Environment ServiceSolution
In your case it should be
oh hey, using 'environment' worked! look at that! That has opened up a whole swathe of possibilities... cheers Dennis! Gotta say, absolutely loving Laravel + Filament, I'd never touched Laravel up until a few weeks ago, the learning curve has been pretty brutal, but it's been the most fun writing code I've had in I don't even know how long!
Learning Laravel, Livewire and Filament at the same time seems like a lot, but as long as you have fun. Even if you already start diving into topics like Dependency Injection. π