DEV Community

Demian Kostelny
Demian Kostelny

Posted on

Laravel & Design Patterns — Practice Series: Facade

In this article, we are going to take a look at how to practically implement the most-used pattern in Laravel — the Facade pattern. So, as always, let’s begin with a definition.

Facade is a structural design pattern that provides a simplified interface to a library, a framework, or any other complex set of classes.

Just imagine that you have installed a custom mailing library into your application that requires object initialization and other function calls to send email. And instead of creating a library class object again and again, and calling all other tasks that you need for sending email, you just create a simple facade class where you will do all this stuff in one function, without the need to work with the library directly.

Introduction

For this article, we are going to install a real library just to demonstrate how you can use this pattern for such cases, so run the following command:

$ composer require league/flysystem
Enter fullscreen mode Exit fullscreen mode

This is a great abstraction package for working with local or remote storage, and now let’s see a bad example without a facade implementation.

Bad example

Let’s imagine that we need to save a file in our controller to local and remote storage using this library in the controller called FileController:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\Filesystem;
use League\Flysystem\FileAttributes;
use Exception;

class FileController extends Controller
{
    public function createFileWithList(Request $request)
    {
        $path = __DIR__ . '/storage';
        $adapter = new LocalFilesystemAdapter($path);
        $filesystem = new Filesystem($adapter);

        // Save file into our local storage
        try {
            $filesystem->write(location: 'example.txt', contents: 'Lorem ipsum dolor sit amet.');
        } catch (Exception $e) {
            throw new Exception("Something went wrong with file upload: " . $e->getMessage());
        }

        // Get files list from storage
        $listing = $filesystem->listContents($path);

        foreach ($listing as $item) {
            $itemPath = $item->path();
            if ($item instanceof FileAttributes) {
                echo "File: $itemPath\n";
            } else if ($item instanceof DirectoryAttributes) {
                echo "Directory: $itemPath\n";
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

As you can see here, we do a lot of different imports and create two different objects to handle file upload and file listing, and also we do “try-catch” for the write function, and make another call to foreach all files and directories from our storage. In our case, each time we want to save a file, we will need to specify the storage path, create new class objects, and again call the write() function — that’s not good.

This is the case when we should use the Facade pattern to separate the library functionality that we need into a separate class that we are going to use for such cases.

Facade pattern implementation

Now it’s time to do everything correctly. First, create a new file in app/Facades/FileFacade.php — that will be our facade class that will be used for file upload with that library:

<?php

namespace App\Domains\Facades;

use League\Flysystem\Local\LocalFilesystemAdapter;
use League\Flysystem\Filesystem;
use League\Flysystem\FileAttributes;
use Exception;

class FileFacade
{
    private $path;
    private LocalFilesystemAdapter $adapter;
    private Filesystem $filesystem;

    public function __construct()
    {
        $this->path = storage_path('app/files');
        $this->adapter = new LocalFilesystemAdapter($this->path);
        $this->filesystem = new Filesystem($this->adapter);
    }

    public function createFile($name, $content)
    {
        $this->filesystem->write(location: $name, contents: $content);
    }

    public function getFilesList()
    {
        $listing = $this->filesystem->listContents($this->path);

        foreach ($listing as $item) {
            $itemPath = $item->path();

            if ($item instanceof FileAttributes) {
                echo "File: $itemPath\n";
            } else if ($item instanceof DirectoryAttributes) {
                echo "Directory: $itemPath\n";
            }
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

Pay attention that for each operation we created a separate function, so in the future we can easily reuse it in our codebase. Now it’s time to rewrite FileController in the right way by using the facade that we just created:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Domains\Facades\FileFacade;

class FileController extends Controller
{
    public function __construct(
        private FileFacade $fileFacade
    ) {}

    public function createFileWithList(Request $request)
    {
        // also we can provide values from $request for this function
        $this->fileFacade->createFile('test.txt', 'my super file');
        $this->fileFacade->getFilesList();
    }
}
Enter fullscreen mode Exit fullscreen mode

Don’t forget to add an endpoint for this controller in your routes/web.php:

<?php

use App\Http\Controllers\FileController;
use Illuminate\Support\Facades\Route;

Route::get('/file/create', [FileController::class, 'createFileWithList']);
Enter fullscreen mode Exit fullscreen mode

Visit this page and check the storage/app/files folder — and you will see that the file was created, which means that our implementation is working properly. We separated our controller from direct interaction with the library and also removed the dependency on the library — that’s a good approach.

Inside Laravel examples

Now that you have understood what the facade pattern is and how it can be used in development, let’s see some examples of Laravel classes that are being used frequently by developers. First example — Http facade:

<?php

namespace App\Domains\Facades;

use Illuminate\Support\Facades\Http;

class GetPostsCommand
{
    private $api = 'https://jsonplaceholder.typicode.com/';

    public function execute()
    {
        $response = Http::get($this->api.'/posts');

        return $response->getBody();
    }
}
Enter fullscreen mode Exit fullscreen mode

Basically, we just did a GET HTTP request using the get() function from the Http facade, and the most interesting thing is that Laravel, in the Http class, is using the Guzzle HTTP library, and to make use of this class easier and simpler, it’s using the facade pattern.

And that’s not the only example of Laravel classes that use this pattern; all classes that are in the Illuminate\Support\Facades namespace are classes with implemented Facade pattern.

Conclusion

This was a simple but practical example of how to use Facade in your Laravel application, pretty easy and nice, which makes your code cleaner and easier for modifications.

Top comments (0)