2

Without knowing how Laravel facades work, based on my PHP knowledge, I tried to extend Storage facade to add some new functionalities.

I have this code:

class MyStorageFacade extends Facade {
    /**
     * Get the binding in the IoC container
     *
     * @return string
     */
    protected static function getFacadeAccessor()
    {
        return 'MyStorage'; // the IoC binding.
    }
}

While booting service provider:

$this->app->bind('MyStorage',function($app){
    return new MyStorage($app);
});

And facade is:

class MyStorage extends \Illuminate\Support\Facades\Storage{
}

When using it:

use Namespace\MyStorage\MyStorageFacade as MyStorage;
MyStorage::disk('local');

I get this error:

FatalThrowableError in Facade.php line 237: Call to undefined method Namespace\MyStorage\MyStorage::disk()

Also tried to extend MyStorage form Illuminate\Filesystem\Filesystem and got the same error in other way:

BadMethodCallException in Macroable.php line 74: Method disk does not exist.

Pankaj Makwana
  • 3,030
  • 6
  • 31
  • 47
Omid
  • 4,575
  • 9
  • 43
  • 74

2 Answers2

3

Your MyStorage class needs to extend FilesystemManager not the Storage facade class.

class MyStorage extends \Illuminate\Filesystem\FilesystemManager {
    ....
}
Marcin Orlowski
  • 72,056
  • 11
  • 123
  • 141
Paras
  • 9,258
  • 31
  • 55
1

A facade is just a convenience class that will convert a static call Facade::method to resolove("binding")->method (more or less). You need to extend from Filesystem, register that in IoC, keep your facade as it is, and use the Facade as a static.

The facade:

class MyStorageFacade extends Facade {      
    protected static function getFacadeAccessor()
    {
        return 'MyStorage'; // This one is fine
    }
}

Your custom storage class:

class MyStorage extends Illuminate\Filesystem\FilesystemManager {
}

In any service provider (e.g. AppServiceProvider)

$this->app->bind('MyStorage',function($app){
   return new MyStorage($app);
});

Then when you need to use it use it as:

MyStorageFacade::disk(); //Should work. 
apokryfos
  • 38,771
  • 9
  • 70
  • 114
  • As I mentioned, I've tested it and get this error: `BadMethodCallException in Macroable.php line 74: Method disk does not exist.` – Omid Mar 12 '17 at 06:14
  • @Omid `disk` is not really defined anywhere though. – apokryfos Mar 12 '17 at 06:17
  • So how `\Storage::disk('local')` works in that case? @apokryfos – Omid Mar 12 '17 at 06:20
  • I think that's bound to a `FilesystemManager` class instead of a `FileSystem` class. Updated the code. – apokryfos Mar 12 '17 at 06:29
  • You're right, It's now working. However, it's odd that facade accessor is returning `filesystem`. @apokryfos – Omid Mar 12 '17 at 06:33
  • It's tricky. Check the source of the `Application` class at https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Application.php#L1068 to see all built in bindings if in doubt of what a facade returns. – apokryfos Mar 12 '17 at 06:41
  • This doesn't work at all.. trying to figure it out for hours.. Can you please update your answer with the namespace/use and where to actually put the bind()? That would be helpful, thanks! – emotality Mar 11 '18 at 11:05
  • @emotality I was basing those on the OPs setup. At any rate I've updated it hopefully it makes more sense now – apokryfos Mar 11 '18 at 11:08