Search code examples
laravellaravel-5laravel-5.3

How to access a packages methods?


I'm developing a laravel package, inside the package I have a repository that deals with the data.

When a user installs the package, how can I get them to interact with the repository in their app?

Should I set up a facade so they can do something like:

SuperPackage::getSomeData();

Or should I use a different way?

The docs state:

When building a third-party package that interacts with Laravel, it's better to inject Laravel contracts instead of using facades. Since packages are built outside of Laravel itself, you will not have access to Laravel's facade testing helpers.

I presume this is just meant for internals of the package, calling the package externally, facades are still ok?


Solution

  • Since you pretty much need to write a Service Provider to get your package integrated into a user's application anyway, I think you should make your package available by dependency injection using contracts. I don't think it hurts to provide a facade for convenience as well, since really it's only one extra file that references something in your service provider.

    Your contract:

    namespace Your\Package;
    
    public interface YourPackageContract
    {
        public function availableMethod();
    }
    

    Your implementation:

    namespace Your\Package;
    
    class YourPackage implements YourContract
    {
        public function availableMethod()
        {
            //  Implement your method
        }
    }
    

    Your service provider:

    namespace Your\Package;
    
    use Illuminate\Support\ServiceProvider;
    
    class YourPackageServiceProvider extends ServiceProvider
    {
        public function register()
        {
            // Tell Laravel that when an instance of YourPackageContract is requested, an instance of YourPackage should be returned
            $this->app->singleton('Your\Package\YourPackageContract', function($app) {
                return new YourPackage();
            });
        }
    
        public function provides()
        {
            return ['Your\Package\YourPackageContract'];
        }
    }
    

    Your Facade:

    namespace Your\Package\Facades;
    
    use Illuminate\Support\Facades\Facade;
    
    class YourPackage extends Facade
    {
        public function getFacadeAccessor()
        {
            return 'Your\Package\YourPackageContract';
        }
    }
    

    Usage in a controller:

    class SomeController
    {
        public function index(YourPackageContract $yourPackage)
        {
            // $yourPackage should now be an instance of YourPackage
            $yourPackage->availableMethod();
    
            // You can also use the Facade which refers to the same instance
            YourPackage::availableMethod();
        }
    }
    

    You could always use the ->alias() method in your service provider if you want to create multiple ways of accessing your class, with more readable names etc.

    Note: I've just written this directly here, I haven't had the chance to test it.