Search code examples
phplaravelfacadeservice-provider

Laravel facade with bind only instantiates once


I'm making a Laravel package and I'm using a service provider and a facade to make my class available.

I want that every time the user calls my class like ImageUpload::myfunc() a new instance of the class ImageUploadManager is created.

When I use app('imageupload')->myfunc() it works the way I want it but i'd like something easier and "prettier" than that.

Is it possible? I'm not new to laravel but I'm somewhat new to ServiceProviders and Facades. From my understanding the only thing I needed to do was call the function bind instead of singleton.

I also understand that the service container is just a glorified array. So it makes sense that the key imageupload is already instantiated so Laravel doesn't do it again, but other packages do it I just don't understand how.

My Facade:

class ImageUpload extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'imageupload';
    }
}

My Service Provider:

public function register(): void
{
    $this->app->bind('imageupload', function ($app) {
       return new ImageUploadManager();
    });
}

In a controller somewhere

ImageUpload::myfunc(); //It's always the same instance

app('imageupload')->myfunc(); //It's a new instance everytime. This is what I want

Solution

  • After researching how other packages do it, I found one that was similar to mine and figured out how they did it.

    Every time my class is called statically I create a new instance of it. I found this solution by looking at this package.

    I changed my facade to this:

    class ImageUpload extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'imageupload';
        }
    
    
        public static function __callStatic($method, $args)
        {
            /** @var \Illuminate\Contracts\Foundation\Application|null */
            $app = static::getFacadeApplication();
            if (!$app) {
                throw new RuntimeException('Facade application has not been set.');
            }
    
            // Resolve a new instance, avoid using a cached instance
            $instance = $app->make(static::getFacadeAccessor());
    
            return $instance->$method(...$args);
        }
    }
    

    I don't know if this is the correct way to do it, it was the way that I found.