Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel: dependency injection in commands

Is dependency injection of a custom class in a command possible?

I'm trying this:

<?php

namespace vendor\package\Commands;

use Illuminate\Console\Command;
use vendor\package\Models\Log;
use vendor\package\Updates\UpdateStatistics;

class UpdatePublishmentStats extends Command
{
    /**
     * The name and signature of the console command.
     *
     * @var string
     */
    protected $signature = 'vendorname:updatePublishmentStats';

    /**
     * The console command description.
     *
     * @var string
     */
    protected $description = 'Updates Twitter followers & Facebook page likes';

    /**
     * Contact implementation
     * @var vendor\package\Update\UpdateStatistics
     */
    protected $stats;

    /**
     * Create a new command instance.
     *
     * @return void
     */
    public function __construct(
        Log $log,
        UpdateStatistics $stats
    ) {
        parent::__construct();
        $this->log = $log;
        $this->stats = $stats;
    }

But when I try to do this:

public function handle()
{
    $this->stats->updateFbStats();

}

I suddenly get Segmentation fault: 11

When I delete the use vendor\package\Updates\UpdateStatistics; part, I don't get that error.

So what am I doing wrong here? Is it not possible to use dependency injection in a command?

like image 859
RW24 Avatar asked Jun 05 '16 22:06

RW24


People also ask

How do I perform dependency injection in Laravel?

In Laravel, dependency injection is the process of injecting class dependencies into a class through a constructor or setter method. This allows your code to look clean and run faster. Dependency injection involves the use of a Laravel service container, a container that is used to manage class dependencies.

What is __ construct in Laravel?

The constructor is a method that is called whenever a new instance of a (PHP) class is instantiated. This is object oriented programming 101.

What service injection is explain in detail with respect to Laravel?

The Laravel service container is a powerful tool for managing class dependencies and performing dependency injection. Dependency injection is a fancy phrase that essentially means this: class dependencies are "injected" into the class via the constructor or, in some cases, "setter" methods.

What is dependency injection in PHP with example?

Dependency injection is a procedure where one object supplies the dependencies of another object. Dependency Injection is a software design approach that allows avoiding hard-coding dependencies and makes it possible to change the dependencies both at runtime and compile time.


2 Answers

You can inject any service in the handle method:

Note that we are able to inject any dependencies we need into the command's handle method.

Source: https://laravel.com/docs/5.8/artisan#command-structure

like image 134
eightyfive Avatar answered Nov 06 '22 17:11

eightyfive


According to the Command Structure section of 5.2 documentation (https://laravel.com/docs/5.2/artisan#writing-commands):

"Note that we are able to inject any dependencies we need into the command's constructor. The Laravel service container will automatically inject all dependencies type-hinted in the constructor."

So I think you're good there, as far as the capability being present and available.

As for getting it to work, for me the segfault points to something wrong with the UpdateStats class, how it's referenced in the service container, or how its being resolved from the service container.

I don't have a definitive answer, but what I would do is try another class and see if I could localize the issue to this particular class, or if the problem happens with others, and then try and debug from there.

Also, if you just can't get that to work, the app() function will resolve items from the service container when you want (although looking through the 5.2 docs I don't see it anymore, so it may be deprecated - I do see $this->app->make() however).

This may work for you if nothing else does:

public function __construct(
    Log $log,
) {
    parent::__construct();
    $this->log = $log;
    $this->stats = app(UpdateStatistics::class);
}

My guess is, however, that you will get a segfault with this as well, as it should try resolving the same class the same way. If you do, then at least the error is a little clearer, and unrelated to auto-injecting feature.

Hope that at least helps a little.


Update on the app() function

So the app() function does not appear to be documented, but I have 5.2 installed right now and the helpers.php file in Illuminate/Foundation definitely has the function:

if (! function_exists('app')) {
    /**
     * Get the available container instance.
     *
     * @param  string  $make
     * @param  array   $parameters
     * @return mixed|\Illuminate\Foundation\Application
     */
    function app($make = null, $parameters = [])
    {
        if (is_null($make)) {
            return Container::getInstance();
        }

        return Container::getInstance()->make($make, $parameters);
    }
}

Unfortunately the API documentation doesn't include any of the helper functions, but the current master, 5.2, and 5.3 versions of the file on Github all have the function:

  • https://github.com/laravel/framework/blob/master/src/Illuminate/Foundation/helpers.php#L91
  • https://github.com/laravel/framework/blob/5.3/src/Illuminate/Foundation/helpers.php#L91
  • https://github.com/laravel/framework/blob/5.2/src/Illuminate/Foundation/helpers.php#L91
like image 37
stratedge Avatar answered Nov 06 '22 17:11

stratedge