简体   繁体   中英

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.)

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.

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.

I had a bit of a play with this (no serious testing) and it looks like it's possible - in fact, I rather like it doing it this way, and look to it in the future. Sample (untested) below:

use App/Models/Foo;

class FooController {

    private $model;

    public function __construct(Foo $model) 
    {
       $this->model = $model;
    }

    public function show(Request $request, $id)
    {
        $foo = $this->model->where($this->model->getKeyName(), '=', $id)->first();

        dd($foo);
    }

    public function store(Request $request)
    {
        $foo = $this->model->newInstance();
        $foo->bar = $request->get('baz');
        $foo->save();
    }

}

The find helpers that are on the eloquent facades, such as find, are nice, but essentially under the hood they are a standard where(...)->get()->first().

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM