Back to Course |
Design Patterns in Laravel 11

Facade: in Route, DB, Gate

Diving deep into Laravel source code reveals more patterns. In this case, we can spot a heavy usage of the Facade pattern.


Route Facade

One of the most interacted Facades - Route. We use it every day to define routes in our application:

Route::resource(...);
Route::get(...);
Route::post(...);
Route::group(...);

And we don't even think about the fact that it is a Facade! Even if the use statement at the top tells us that:

use Illuminate\Support\Facades\Route;

This was made into a Facade to allow us to use the Route class without creating a new instance of it:

(new Route)->get(...);

Just imagine how much more code we would have to write if we had to create a new instance of the Route class every time we wanted to define a new route.

So this is where Facades come in handy. They allow us to use the classes without creating new instances of them:

Illuminate/Support/Facades/Route.php

class Route extends Facade
{
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'router';
}
}

And of course, in order to use the Route Facade - there is some PHP magic happening behind the scenes:

Illuminate/Support/Facades/Facade.php

abstract class Facade
{
// ...
 
/**
* Handle dynamic, static calls to the object.
*
* @param string $method
* @param array $args
* @return mixed
*
* @throws \RuntimeException
*/
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);
}
}

This magic method allows us to call methods on any Facade as if we were calling them on the actual class.


DB Facade

Another common Facade is the DB Facade. We use it to interact with the database:

DB::table('users')->get();
DB::table('users')->where('name', 'John')->get();
DB::transaction(...);
DB::beginTransaction();

Once again, this feels like we are using a class, but in reality, we are using a Facade. In this case, the Facade behind it - has a unique method, prohibitDestructiveCommands:

Illuminate/Support/Facades/DB.php

class DB extends Facade
{
/**
* Indicate if destructive Artisan commands should be prohibited.
*
* Prohibits: db:wipe, migrate:fresh, migrate:refresh, and migrate:reset
*
* @param bool $prohibit
* @return void
*/
public static function prohibitDestructiveCommands(bool $prohibit = true)
{
FreshCommand::prohibit($prohibit);
RefreshCommand::prohibit($prohibit);
ResetCommand::prohibit($prohibit);
WipeCommand::prohibit($prohibit);
}
 
/**
* Get the registered name of the component.
*
* @return string
*/
protected static function getFacadeAccessor()
{
return 'db';
}
}

And as the method name suggests, it prohibits destructive commands. This is an excellent example of how we can extend the functionality of the Facade without changing the actual class.


Gate Facade

Last but not least, the Gate Facade. We use it to define authorization policies:

Gate::define(...);
Gate::authorize(...);
Gate::allows(...);
Gate::denies(...);
Gate::any(...);

These are all Facade methods, and using them is really common:

Controller

public function create()
{
Gate::authorize('create', Post::class);
 
return view('posts.create');
}

Also, did you know you're using Facade in Blade templates? The @can directive acts as the Gate Facade:

@can(...)
@cannot(...)

Or even, if you ever used ->can() on your user Model:

$user->can(...);
Auth::user()->can(...);

All of these are specific methods that we use, but in the end, they still call it the Gate Facade.


Abstract class Facade

But what are Facades? Why do they all extend the same class - Illuminate\Support\Facades\Facade?

In short, this class provides additional functionality to the Facades. For example, in testing - we can mock them:

Cache::shouldReceive('get')
->once()
->with('key')
->andReturn('value');

This is possible because the Facade class has a shouldReceive method:

Illuminate/Support/Facades/Facade.php

// ...
 
/**
* Initiate a mock expectation on the Facade.
*
* @return \Mockery\Expectation
*/
public static function shouldReceive()
{
$name = static::getFacadeAccessor();
 
$mock = static::isMock()
? static::$resolvedInstance[$name]
: static::createFreshMockInstance();
 
return $mock->shouldReceive(...func_get_args());
}
 
// ...

This is just one example of how the Facade class extends the functionality of Facades and sets some default workflows for them.

If you are interested, we strongly recommend you to check the Facade class in the Laravel source code