How to Create a Facade Class with Laravel

How do I create a facade class with Laravel?

Step 1

Create a folder called facades in your app folder (app/facades).

Step 2

Add the facade folder to your composer autoload.

"autoload": {
"classmap": [
...
"app/facades"
]
},

Step 3

Create a Facade file in that folder (FooFacade.php) and add this content:

<?php
use Illuminate\Support\Facades\Facade;

class MyClass extends Facade {
protected static function getFacadeAccessor() { return 'MyClassAlias'; } // most likely you want MyClass here
}

Step 4

Create a model in app/models (MyClass.php).

<?php
namespace MyNamespace;

use Eloquent; // if you're extending Eloquent

class MyClass extends Eloquent {
...
}

Step 5

Create a new service provider (you can create a folder in app called serviceproviders and add it to composer autoload) (app/models/MyClassServiceProvider.php).

<?php
use Illuminate\Support\ServiceProvider;

class MyClassServiceProvider extends ServiceProvider {
/**
* Register the service provider.
*
* @return void
*/
public function register() {
$this->app->bind('MyClassAlias', function(){
return new MyNamespace\MyClass;
});
}
}

Here you can add new binding if you want another facade (don't forget to create a facade file if so).

Step 6

Add the service provider to the providers array in config/app.php.

'providers' => array(
...
'MyServiceProvider'
)

Step 7

Run composer dump so we can access our new classes.

Step 8

You can now access MyClassAlias::method() as a facade.

How do I inject a request into a facade class in Laravel?

Looks like this worked out:

In the ParamsServiceProvider, instead of using App::bind to instantiate the Params class, do this instead:

public function register()
{
App::alias(Params::class, 'params');
}

then the request object will be injected properly into the facade.

How and where does the Facade class property $app get set?

Found it there is a setFacadeApplication( $app ) method which is set on the initialization of the Laravel App.

How facades work in laravel? How the methods can be accessed with ::

The magic happens in Facade's __callStatic function.

public static function __callStatic($method, $args)
{
$instance = static::getFacadeRoot();
if (! $instance) {
throw new RuntimeException('A facade root has not been set.');
}
return $instance->$method(...$args);
}

It first gets the appropriate instance, and then simply invokes the requested method with the given arguments.

Adding Facades before namespace in Laravel , How it works?

What you are describing is Laravels Real-Time Facades.

You can find documentation of the functionality here:
https://laravel.com/docs/6.x/facades#real-time-facades

How laravel uses object as an array in Facade class

Clicking through the Laravel source, I found this. As you can see, ApplicationContract (the private static $app from your question) is implemented by Application. This is in turn derived from Container, which implements the PHP core ArrayAccess interface. Carefully implementing this whole chain eventually makes Applicatin accessible like an array.

Turns out it boils down to good ole' object oriented programming :)

// Illuminate/Foundation/Application.php
class Application extends Container implements ApplicationContract, HttpKernelInterface
^^^^^^^^^ ^-> the private static $app in your question.

// Illuminate/Container/Container.php
class Container implements ArrayAccess, ContainerContract
^^^^^^^^^^^

// PHP core ArrayAccess documentation
/**
* Interface to provide accessing objects as arrays.
* @link http://php.net/manual/en/class.arrayaccess.php
*/
interface ArrayAccess {

How to Set Up Facades in Laravel 5.2 (outside of /app)

This may not be the only way to implement facades in Laravel 5, but here is how I did it.

We're going to create a custom Foo facade available in the Foobar namespace.

1. Create a custom class

First, for this example, I will be creating a new folder in my project. It will get its own namespace that will make it easier to find.

In my case the directory is called Foobar:

Sample Image

In here, we'll create a new PHP file with our class definition. In my case, I called it Foo.php.

<?php
// %LARAVEL_ROOT%/Foobar/Foo.php

namespace Foobar;

class Foo
{
public function Bar()
{
return 'got it!';
}
}

2. Create a facade class

In our fancy new folder, we can add a new PHP file for our facade. I'm going to call it FooFacade.php, and I'm putting it in a different namespace called Foobar\Facades. Keep in mind that the namespace in this case does not reflect the folder structure!

<?php
// %LARAVEL_ROO%/Foobar/FooFacade.php

namespace Foobar\Facades;

use Illuminate\Support\Facades\Facade;

class Foo extends Facade
{
protected static function getFacadeAccessor()
{
return 'foo'; // Keep this in mind
}
}
  • Bear in mind what you return in getFacadeAccessor as you will need that in a moment.

Also note that you are extending the existing Facade class here.

3. Create a new provider using php artisan

So now we need ourselves a fancy new provider. Thankfully we have the awesome artisan tool. In my case, I'm gonna call it FooProvider.

php artisan make:provider FooProvider

Bam! We've got a provider. Read more about service providers here. For now just know that it has two functions (boot and register) and we will add some code to register. We're going to bind our new provider our app:

$this->app->bind('foo', function () {
return new Foo; //Add the proper namespace at the top
});

So this bind('foo' portion is actually going to match up with what you put in your FooFacade.php code. Where I said return 'foo'; before, I want this bind to match that. (If I'd have said return 'wtv'; I'd say bind('wtv', here.)

Furthermore, we need to tell Laravel where to find Foo!

So at the top we add the namespace

use \Foobar\Foo;

Check out the whole file now:

<?php
// %LARAVEL_ROOT%/app/Providers/FooProvider.php

namespace App\Providers;

use Illuminate\Support\ServiceProvider;
use Foobar\Foo;

class FooProvider extends ServiceProvider
{
/**
* Bootstrap the application services.
*
* @return void
*/
public function boot()
{
//
}

/**
* Register the application services.
*
* @return void
*/
public function register()
{
$this->app->bind('foo', function () {
return new Foo;
});
}
}
  • Make sure you use Foobar\Foo and not Foobar\Facades\Foo - your IDE might suggest the wrong completion.

4. Add our references to config/app.php

Now we have to tell Laravel we're interested in using these random files we just created, and we can do that in our config/app.php file.

  1. Add your provider class reference to 'providers': App\Providers\FooProvider::class

  2. Add your facade class reference to 'aliases': 'Foo' => Foobar\Facades\Foo::class

Remember, in aliases, where I wrote 'Foo', you will want to put the name you want to reference your facade with there. So if you want to use MyBigOlFacade::helloWorld() around your app, you'd start that line with 'MyBigOlFacade' => MyApp\WhereEverMyFacadesAre\MyBigOlFacade::class

5. Update your composer.json

The last code change you should need is to update your composer.json's psr-4 spaces. You will have to add this:

    "psr-4": {
"Foobar\\" : "Foobar/",
// Whatever you had already can stay
}

Final move

Okay so now that you have all that changed, the last thing you need is to refresh the caches in both composer and artisan. Try this:

composer dumpautoload
php artisan cache:clear

Usage & A Quick Test:

Create a route in app/routes.php:

Route::get('/foobar', 'FooBarController@testFoo');

Then run

php artisan make:controller FooBarController

And add some code so it now looks like this:

<?php

namespace App\Http\Controllers;

use Foobar\Facades\Foo;

use App\Http\Requests;

class FooBarController extends Controller
{
public function testFoo()
{
dd(Foo::Bar());
}
}

You should end up with the following string:

Sample Image


Troubleshooting

  • If you end up with and error saying it cannot find the class Foobar\Facades\Foo, try running php artisan optimize

Why create a facade in laravel instead of calling a method directly?

A Facade in Laravel is only a convenient way to get an object from the Service Container and call a method on it.

So calling a Facade like this :

//access session using a Facade 
$value = Session::get('key');

Is like doing:

//access session directly from the Service Container
$value = $app->make('session')->get('key');

As the Facade resolves the session key out of the Service Container and call the method get on it

Once understood what a Facade does, you should understand what is the Service container and what are the benefits of using it

The Service Container in Laravel cloud be a Dependency Injection Container and a Registry for the application

The advantages of using a Service Container over creating manually your objects are stated in one of my previous answers and in the doc page, but briefly:

  • Capacity to manage class dependencies on object instantation
  • Binding of interfaces to concrete classes, so that when a interface is requested in your program, a concrete class is instantiated automatically by the service container. Changing the concrete class on the binding, will change the concrete objects instantiated through all your app
  • Possibility to create single intances and get them back later (Singleton)

What is Facades used in Laravel?

Props to SitePoint for sharing such informative and helpful knowledge about facades in Laravel.

The facade pattern is a software design pattern that is often used in object-oriented programming.

A facade is a class wrapping a complex library to provide a simpler and more readable interface to it.

Facade pattern

Facades in Laravel

Facades provide a "static" interface to classes that are available in the application's service container. Laravel ships with many facades which provide access to almost all of Laravel's features. Laravel facades serve as "static proxies" to underlying classes in the service container, providing the benefit of a terse, expressive syntax while maintaining more testability and flexibility than traditional static methods.

How Facades Are implemented in Laravel

Every service inside the container has a unique name. In a Laravel application, to access a service directly from the container, we can use the App::make() method or the app() helper function.

<?php

App::make('some_service')->methodName();

In Laravel, all services have a facade class. These facade classes extend the base Facade class which is part of the Illuminate/Support package. The only thing that they need to implement is the getFacadeAccessor method, which returns the service name inside the container.



Related Topics



Leave a reply



Submit