Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel, Dependency Injection, and Eloquent

What the right/best way to use laravel's dependency injection system with multiple-instance objects like CRUD models?

Current fashion in some corners of PHP-land say the following code is "bad"

function someMethod()
{
    /* .. stuff ... */
    $object = new \App\SomeModel;
    $object->some_prop = 'some value';
    $object->save();
    /* .. other stuff ... */
}

It's bad because this method is now dependent on that new object instantiation. The current fashion says objects ought to be injected via some sort of dependency injection system, like Laravel's automatic constructor dependency injection.

However -- injecting eloquent models seems problematic

/*...*
public function __construct(\App\SomeModel $object)
{
    $this->someModel = $object;
}

function someMethod()
{
    /* .. stuff ... */
    $object = $this->someModel;
    $object->some_prop = 'some value';
    $object->save();
    /* .. other stuff ... */
}  
/*...*/           

It's not clear if Laravel's automatic constructor dependency injection creates new instances each time, or if the objects injected are single instance objects. It also doesn't handle situations where you want to use Eloquent's static helpers

function someMethod($object_id)
{
    //another dependency
    \App\SomeModel::find($object_id);

    //but this doesn't work
    $this->someModel->find($object_id);
}    

Is there a generally accepted way to handle this in a Laravel application? Some people say you should inject factories. Other people say repositories. I'd like to know what the general practice is with Laravel developers and if Laravel ships with anything that can help out here (base factory/repository implementations, etc.)

like image 995
Alan Storm Avatar asked Oct 29 '22 08:10

Alan Storm


2 Answers

Thanks to some help from the LaraChat Slack I figured this one out on my own.

It turns out that, in addition to automatic constructor dependency injection, Laravel has a special form of dependency injection that works with any of a router's callback methods/functions.

Consider this code sample

Route::get('api/users/{user?}', function (App\User $user) {
    return $user->email;
});

If you setup your route string with a variable ({user}), Laravel will scan your route handler's (above, an anonymous function, but it works with controller methods as well) parameters for a type hint whose short class name matches the variable name (App\User above). If found, instead of passing in the parameter from URL, Laravel will instantiate a loaded Eloquent object. If an optional parameter is ommited, you'll get a blank object of the specified type.

like image 50
Alan Storm Avatar answered Nov 15 '22 06:11

Alan Storm


This extensive discussion of Laravel DI is great. Covers the use of classes and interfaces and more. Best reference I've found. https://gist.github.com/davejamesmiller/bd857d9b0ac895df7604dd2e63b23afe

Laravel has a powerful Inversion of Control (IoC) / Dependency Injection (DI) Container. Unfortunately the official documentation doesn't cover all of the available functionality, so I decided to experiment with it and document it for myself. The following is based on Laravel 5.4.26 - other versions may vary.

like image 31
instance Avatar answered Nov 15 '22 05:11

instance