Use of service providers within controllers in Laravel 5.2

wiredolphin picture wiredolphin · Jun 27, 2016 · Viewed 8.4k times · Source

As for the title I've goggled about two hours searching for a efficient answer and read repeatedly the official documentation, but without any step further, considering I'm relatively new to the framework. The doubt arise while searching for a correct way to share some code between controllers and i stumbled in service providers, so:

  1. I've created say a MyCustomServiceProvider;
  2. I've added it to the providers and aliases arrays within the app.php file;
  3. finally I've created a custom helpers class and registered it like:

    class MyCustomServiceProvider extends ServiceProvider
    {
        public function boot()
        {
            //
        }
    
        public function register()
        {
            $this->app->bind('App\Helpers\Commander', function(){
    
                return new Commander();
    
            });
        }
    }
    

So far, however, if I use that custom class within a controller I necessarily need to add the path to it through the use statement:

use App\Helpers\Commander;

otherwise I get a nice class not found exception and obviously my controller does not his job.
I suspect there's something which escapes to me on service providers! :-)

Answer

tkausl picture tkausl · Jun 27, 2016

So far, however, if I use that custom class within a controller I necessarily need to add the path to it through the use statement:

`use App\Helpers\Commander;`

otherwise I get a nice class not found exception and obviously my controller does not his job.

Yes, that's how it works. If you don't want to use the full name, you can use a Facade instead.

Create the Facade class like this:

class Commander extends Facade
{
    protected static function getFacadeAccessor() { return 'commander'; }
}

register the service:

$this->app->singleton('commander', function ($app) {
    return new Commander();
});

add the alias to your config/app.php:

'aliases' => [
    //...
    'Commander' => Path\To\Facades\Commander::class,
    //...
],

and use it like a Facade:

\Commander::doStuff();

On why your code still works, even when you remove the bind:

When you type-hint a parameter to a function, and Laravel does not know about the type you want (through binding), Laravel will do its best to create that class for you, if it is possible. So even though you didn't bind the class, Laravel will happily create a instance of that class for you. Where you actually need the binding is when you use interfaces. Usually, you'd not type-hint specific classes but a interface. But Laravel can not create a instance of an interface and pass it to you, so Laravel needs to know how it can construct a class which implements the interface you need. In this case, you'd bind the class (or the closure which creates the class) to the interface.