DEV Community

Cover image for Design Patterns in PHP: Facade (with Laravel)
Ahmed Ashraf
Ahmed Ashraf

Posted on

Design Patterns in PHP: Facade (with Laravel)

Design patterns are very important for every developer. it solves very common problems in every project you build.

Facade pattern definition:

Facade helps you to hide any complex implementation of a class to get an instance of it

Wikipedia:

a facade is an object that serves as a front-facing interface masking more complex underlying or structural code

The Problem:

Let's say we have a CMS and with every new post, we want to tweet about it.

First, we will use dg/twitter-php library to send tweets. from the README it says the following code should post a tweet

use DG\Twitter\Twitter;

$twitter = new Twitter($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);

$twitter->send('I am fine today.');

Notice here every time we need to get a twitter instance we need to pass some data considered secret. and we don't want to pass them every time we need to send a tweet.

also, we don't need a Factory (Factory Pattern) as we only want to send tweets and using a factory here would be an extra layer of complexity that we don't need.

so the Facade pattern can help us hide the complexity of creating an instance by creating this Facade class

class TwitterFacade 
{
  public static function get()
  {
    return new Twitter($consumerKey, $consumerSecret, $accessToken, $accessTokenSecret);
  }
}

as we are using laravel. let's put the secrets in config/services.php

'twitter' => [
    'api_key' => env('TWITTER_API_KEY'),
    'api_secret' => env('TWITTER_API_SECRET'),
    'api_token' => env('TWITTER_Access_TOKEN'),
    'api_token_secret' => env('TWITTER_Access_TOKEN_SECRET'),
],

and then let's update our facade class to use the config like following

class TwitterFacade 
{
  public static function get()
  {
      $config = config('services.twitter');
      return new Twitter($config['api_key'], $config['api_secret'], $config['api_token'], $config['api_token_secret']);
  }
}

and now whenever we want to send tweets we would just write one single line

TwitterFacade::get()->send('Test tweet from a facade class');

Implement Facade with Laravel

Laravel is supporting the Facade pattern and its part of its core system. if you open config/app.php and scroll to the aliases you would see a bunch of Facades

'aliases' => [

    'App' => Illuminate\Support\Facades\App::class,
    'Arr' => Illuminate\Support\Arr::class,
    'Artisan' => Illuminate\Support\Facades\Artisan::class,
    'Auth' => Illuminate\Support\Facades\Auth::class,
    'Blade' => Illuminate\Support\Facades\Blade::class,
    'Broadcast' => Illuminate\Support\Facades\Broadcast::class,
    'Bus' => Illuminate\Support\Facades\Bus::class,
    'Cache' => Illuminate\Support\Facades\Cache::class,
    'Config' => Illuminate\Support\Facades\Config::class,
    'Cookie' => Illuminate\Support\Facades\Cookie::class,
    'Crypt' => Illuminate\Support\Facades\Crypt::class,
    'DB' => Illuminate\Support\Facades\DB::class,
    'Eloquent' => Illuminate\Database\Eloquent\Model::class,
    'Event' => Illuminate\Support\Facades\Event::class,
    'File' => Illuminate\Support\Facades\File::class,
    'Gate' => Illuminate\Support\Facades\Gate::class,
    'Hash' => Illuminate\Support\Facades\Hash::class,
    'Lang' => Illuminate\Support\Facades\Lang::class,
    'Log' => Illuminate\Support\Facades\Log::class,
    'Mail' => Illuminate\Support\Facades\Mail::class,
    'Notification' => Illuminate\Support\Facades\Notification::class,
    'Password' => Illuminate\Support\Facades\Password::class,
    'Queue' => Illuminate\Support\Facades\Queue::class,
    'Redirect' => Illuminate\Support\Facades\Redirect::class,
    'Redis' => Illuminate\Support\Facades\Redis::class,
    'Request' => Illuminate\Support\Facades\Request::class,
    'Response' => Illuminate\Support\Facades\Response::class,
    'Route' => Illuminate\Support\Facades\Route::class,
    'Schema' => Illuminate\Support\Facades\Schema::class,
    'Session' => Illuminate\Support\Facades\Session::class,
    'Storage' => Illuminate\Support\Facades\Storage::class,
    'Str' => Illuminate\Support\Str::class,
    'URL' => Illuminate\Support\Facades\URL::class,
    'Validator' => Illuminate\Support\Facades\Validator::class,
    'View' => Illuminate\Support\Facades\View::class,

],

Now let's create a new class in App/Facades/TwitterFacade.php and put the following content

namespace App\Facades;

use Illuminate\Support\Facades\Facade;

class TwitterFacade extends Facade 
{
    protected static function getFacadeAccessor()
    {
        return 'twitter-poster';
    }
}

notice that we are extending Facade from Illuminate namespace and then we implemented getFacadeAccessor. we choose 'twitter-poster' as the name of the Twitter object that we want to use.

Now let's jump to the AppServiceProvider to bind the 'twitter-poster' to Twitter. in AppServiceProvider at Register method add the following

use DG\Twitter\Twitter;

public function register()
{
    $this->app->bind('twitter-poster',function(){
        $config = config('services.twitter');
        return new Twitter($config['api_key'], $config['api_secret'], $config['api_token'], $config['api_token_secret']);
    });
}

Now you can see the connection. first, we registered 'twitter-poster' and bind it to an instance of a Twitter class.

The final usage of our facade will be like following

Route::get('/tweet',function(){

    \App\Facades\TwitterFacade::send('Hello from ahmedash.com: Facade design pattern article');

});

Conclusion

We learned what is Facade and what problem does it solve and how to use it with Laravel

Discussion (8)

Collapse
phambinh217 profile image
Phạm Quang Bình

I think use $this->app->singleton is better. Because your Twitter service is never changes, it should be creating only one on first time.

Collapse
ahmedash95 profile image
Ahmed Ashraf Author

Correct. but that was not the purpose of the article. it makes sense though

Collapse
innoflash profile image
Innocent Mazando

Nice post @ashraf .

I think the facade name did not need a Facade suffix. Convectionally it should plainly be what it represents like a simple Twitter.

Examples are the Mail and Auth facades :)

Thanks for the post.

youtube.com/watch?v=zR6JnwH7MSQ

Collapse
ahmedash95 profile image
Ahmed Ashraf Author

Thanks for the feedback. you are right but few months ago I found it useful to follow Spatie naming classes guide guidelines.spatie.be/code-style/la... as it really helps to just find your target. if you have a Model, Controller, Facade, and Service for Twitter naming them Twitter, TwitterFacade, TwitterController, and TwitterService would help a lot to just read and get what each class referring to

Collapse
alamriku profile image
alamriku

It would be much informative if a little distinguish added on the post about proxy and facade pattern. why not using proxy.
I am a confused learner on design patterns they always like similar can't get the big picture.

Collapse
iqstudioteharn profile image
alireza

Nice explanation

Collapse
aliadhillon profile image
Ali A. Dhillon

Really helpful, thanx.

Collapse
ahmedash95 profile image
Ahmed Ashraf Author • Edited

I'm glad you find it helpful