Resolve classes from Laravel's Container
My Avatar

Laravel's Container

Laravel's Container is without a doubt one of the most powerful tools provided by the framework. If you've ever used Laravel before, you've used the service Container without even knowing it. Behind the scenes Laravel resolves all your controller classes from the Container, that's the reason you can type hint any class and get an instance really easily.

Resolving a class from the Container

Resolving a class from the Container is very easy with Laravel and there is actually a few ways it can be done. Choose whichever you like best, and stick with it.

// Using the App Facade
App::make('Slack\Api');

// Using the app helper function
app('Slack\Api');

// Using the resolve helper function
resolve('Slack\Client');
<?php

namespace Slack;

class Api
{
    public function __construct(Class $dependency)
    {
        $this->dependency = $dependency;
    }
}

The Container will notice there's a type hint in our constructor and it will try to resolve that dependency and pass it into the class.

Not all dependencies will be resolvable by the Container

What if there's a dependency that can't (or shouldn't) be solved by the Container? Well, you can pass an array as the second parameter with any data that should be sent to the class.

To get a better idea of where this would be necessary, let's explore a real open source poject. We'll use a package I discovered a few weeks ago, Onboard, created by @calebporzio.

Let's take a look at at the OnboardingManager class, specifically the constructor:

<?php

namespace Calebporzio\Onboard;

class OnboardingManager
{
    /**
    * Create the Onboarding Manager (should always be a singleton).
    *
    * @param  mixed $user The parent app's user model.
    * @param  \Calebporzio\Onboard\OnboardingSteps $onboardingSteps
    */
    public function __construct($user, OnboardingSteps $onboardingSteps)
    {
        $this->steps = $onboardingSteps->steps($user);
    }

    // rest of class method...
}

Notice how we aren't type hinting the $user dependency, so the Container wouldn't know how to fetch this dependency for us. Instead, we'll need to pass it in when resolving the class from the Container.

Let's resolve the class from the Container

The package has a GetsOnboarded trait that you can use in your User model, it has just an onboarding method.

<?php

namespace Calebporzio\Onboard;

use Illuminate\Support\Facades\App;

/**
 * This is the trait to be added to the app's User class.
 */
trait GetsOnboarded
{
    /**
    * This provides a pathway for the package's API
    *
    * @return  \Calebporzio\Onboard\OnboardingManager $onboarding
    */
    public function onboarding()
    {
        return App::make(OnboardingManager::class, ['user' => $this]);
    }
}

Notice how we're using the App Facade to resolve the class from the Container so that the type hinted OnboardingSteps dependency gets passed in, but we manually pass in the value for the $user dependency.

For readability Laravel also offers an alias to the App::make method called makeWith which simply calls the make method behind the scenes.

Know you can start resolving classes from the Container and have all their dependencies resolved automatically for you. You have many ways to access the Container, using the App facade with the make method or the app or resolve helper functions. When within a Service Provider you can even access the Container with $this->app.

I'll keep writing more about using the Container so if you're interested, follow me on Twitter to get alerted once the next post goes live, I'm @wilburpowery on there.

Published on: May 17, 2018

Tags: php laravel Container IOC

Want to chat? I'm @wilburpowery on Twitter.