How To Use Adapter Pattern in Laravel

How To Use Adapter Pattern In Laravel

Laravel Design Patterns ( 2 Lessons )

There are various ways to structure the code and project for your web application. But it is usually a good idea to follow common design patterns because it will make your code easier to manage and easier for others to understand.

see full series
  1. How to use Repository Pattern in Laravel
  2. How To Use Adapter Pattern in Laravel

In this post, we will look at how we can use the Adapter Pattern in Laravel. Throughout this post, we will look at the usage and benefits of this pattern using a real-world example.

One thing we can not neglect when creating web application is the Change, it can be in requirements or the third party APIs you are relying your code on. You might think your system is designed perfectly, there are always chances that you will get a new request for a change in your code which will ruin your whole application design.

The Adapter Pattern is a design pattern which deals with the change.

Design Pattern – Big Word 😕

Design Pattern big word isn’t. Before diving into this post, let’s find out what is a design pattern. Accoring to Wikipedia:

In software engineering, a software design pattern is a general, reusable solution to a commonly occurring problem within a given context in software design.

In simple word, a design pattern is a solution or approach to deal with the commonly occurring problems while you are developing software.

What is Adapter Pattern?

The Adapter Pattern (also called wrapper pattern) falls under the category of Structural Patterns which teaches us how to construct classes and how they should be structured in order to manage or extend them easily.

In Adapter pattern, we convert the interface of a class into another interface that the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.

Sometimes we want to use existing code but the interface does not match to your requirement. For example, we want to use a third party package without re-writing our existing code. I highlighted the word “existing” because the main intent of the Adapter Pattern is to deal with existing code, not when you are writing new classes.

The Adapter Pattern has multiple participants:

  • Client: The client is the class or object that want to consume the Adaptee public API.
  • Adapter: The adapter provides a common interface between the adaptee and it’s clients.
  • Adaptee: The adaptee is an object from a different module or third party library.

The biggest advantage of the Adapter Pattern is that it allows us to decouple our client code from the adaptee implementation.

This particular pattern can be used when your code is dependent on some external API, or any other class that is prone to change frequently.

One real-life example of Adapter Pattern could be the smartphone chargers. We all know that we can not use an iPhone charger with Samsung phones and vice versa. If you want to use one charger with both types of phones then, you will need an adapter something like below.

Mobile Phones Adapter
Mobile Phones Adapter

The Problem

It would be ideal to make use of a practical scenario to understand the process and components of the Adapter pattern, so assume that we have a common interface for checking the product stock for our website.

I will keep this example super simple, so you can have a better understanding of how and when to use Adapter Pattern.

Let’s assume we have service class to check the stock for a product and we are currently using it in the controller like below:

// StockCheckController.php
use Illuminate\Http\Request;
use App\Services\DatabaseStockCheck;

class TestController extends Controller
{
    public function index(Request $request, DatabaseStockCheck $databaseStockCheck)
    {
        $sku = $request->input('sku');

        $stock = $databaseStockCheck->getStock($sku);

        return response()->json($stock);
    }
}

Here is the service class DatabaseStockCheck:

// DatabaseStockCheck.php
namespace App\Services;

use App\Product;

class DatabaseStockCheck
{
    public  function getStock($sku)
    {
        // Some database queries to find the product stock
        $product = Product::whereSku($sku)->first();

        return $product->qty;
    }
}
I am using a very simple example, in real life application you might be dealing with a class with several methods.

As you can see, in controller’s index method we are getting product SKU from request object and passing it to our DatabaseStockCheck service to return the current stock level for the given product. Our DatabaseStockCheck service class is simply finding the product and returning the current quantity. Simple isn’t.

Now my Manager asked me to add extra functionality to check product stock from the company’s ERP database as well. As soon as I receive this request, I will spot some problems with the above code.

  • Firstly, we have to make changes to our controller to make request to ERP database.
  • I don’t know if the ERP’s database API implements the same method getStock(). As we can’t ask the third party to modify there class.
  • Because I have to add another service, I have to modify DatabaseStockCheck class.
  • We don’t know if the ERP’s API will provide the correct data type we want.

We can tackle all the above problems using the Adapter pattern. For the sake of this post, I will assume below is the vendor’s ERP API class, which we have to use and we don’t have control over this file to make any changes.

// Dummy Vendor class

namespace App\Vendor;

class Erp
{
    protected $sku;

    public function __construct($sku)
    {
        $this->sku = $sku;
    }

    public function checkStock()
    {
        // API's some magic here return the data
        return [
            'sku'    => $this->sku,
            'status' => true,
            'qty'    => 101
        ];
    }
}

As you can see this class use it’s own checkStock() method and return an array. How the data is passed to this class and return the stock is completely up to this API. There is no way we can make this compatible with our service class as both implement different methods.

Let’s start to make changes to our application and use the Adapter Pattern.

Implementing Adapter Pattern In Laravel

At the moment we know two points about stock checking:

  • We need to get the stock by product sku.
  • Stock returned from the database or API should be in right format.

First thing, we will create a new interface called StockCheckerInterface like below:

namespace App\Interfaces;

interface StockCheckerInterface
{
    public function getStock($sku);
}

Now we will create a new class named DatabaseStockCheckAdapter which will implement the StockCheckerInterface interface like below.

namespace App\Services;

use App\Product;
use App\Interfaces\StockCheckerInterface;

class DatabaseStockCheckAdapter implements StockCheckerInterface
{
    public  function getStock($sku)
    {
        // Some database queries to find the product stock
        $product = Product::whereSku($sku)->first();

        return $product->qty;
    }
}

Next step, we will create a new class called ErpStockCheckAdapter which also implement the StockCheckerInterface interface and use the third party class Erp to make a request to api like below:

namespace App\Services;

use App\Vendor\Erp;
use App\Interfaces\StockCheckerInterface;

class ErpStockCheckAdapter implements StockCheckerInterface
{
    public function getStock($sku)
    {
        // Instantiating the class
        $erp = new Erp($sku);
        // Making request to get the stock using third party method
        $result = $erp->checkStock();
        // Returning the stock quantity we wanted
        return $result['qty'];
    }
}

Now we have two classes which both implement a common interface, now we need to bind the interface to these classes, which we can do using Service Providers in AppServiceProvider.

namespace App\Providers;

use App\Services\ErpStockCheckAdapter;
use App\Interfaces\StockCheckerInterface;
use App\Services\DatabaseStockCheckAdapter;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Register any application services.
     *
     * @return void
     */
    public function register()
    {
        $this->app->singleton(StockCheckerInterface::class, function ($app) {
            switch ($app->make('config')->get('services.stock-checker')) {
                case 'database':
                    return new DatabaseStockCheckAdapter;
                case 'erp':
                    return new ErpStockCheckAdapter;
                default:
                    throw new \RuntimeException("Unknown Stock Checker Service");
            }
        });
    }

    /**
     * Bootstrap any application services.
     *
     * @return void
     */
    public function boot()
    {
        //
    }
}

In AppServiceProvider, we are binding our StockCheckerInterface to our DatabaseStockCheckAdapter and ErpStockCheckAdapter classes based on the configuration values.

Next, we will add a configuration value in config/services.php file like below:

'stock-checker' => 'database',

Let’s quickly adjust our controller to start using the StockCheckerInterface interface.

// StockCheckController.php
use Illuminate\Http\Request;
use App\Interfaces\StockCheckerInterface;

class TestController extends Controller
{
    public function index(Request $request, StockCheckerInterface $stockChecker)
    {
        $sku = $request->input('sku');

        $stock = $stockChecker->getStock($sku);

        return response()->json($stock);
    }
}

As you can see in our controller’s method we are injecting the StockCheckerInterface using type hinting and then simply calling the getStock() method to return stock in JSON format.

Now if you change the stock-checker value from database to erp, you will get the correct stock value.

After making all these changes and implementing the Adapter Pattern in Laravel application:

  • We don’t have to change the controller code.
  • New stock checker services can be added easily.
  • All services will implement a common interface.

Conclusion

The Adapter pattern is also known as a wrapper pattern because it wraps an existing interface inside of the interface the client expects. You might find the Adapter Pattern useful when you don’t have the existing code but most likely this pattern will be used in the case of existing code.

One drawback of this pattern is, if you have two classes which implement so many methods it will be very hard to adapt which can leave your Adapter Pattern broken. Adapter pattern should always be used when the adaptee and client have common goal.

If you have any question or suggestion to improve this post, please leave your feedback in the comment box below.

3 comments on “How To Use Adapter Pattern in Laravel

  1. All I have to say It’s thanks for sharing your kwonledge. I hope to continue Reading this kind of post from you.
    Have a nice day!

  2. I watched some videos and read so many articles, but nothing helped me to understand the adapter pattern, but your article helped me to understand it 100 percent.
    All I want to say is thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

When sharing a code snippet please wrap you code with pre tag and add a class code-block to it like below.
<pre class="code-block">you code here</pre>

*
*

This site uses Akismet to reduce spam. Learn how your comment data is processed.