Becoming a better Laravel developer by using the SOLID design principles. Part 2
Tags: laravel, design, oop, solid
Published: 2020-07-22 04:33:40

This article is part 2 of **Becoming a better Laravel developer by using the SOLID design principles** article series. You can see part one **S - Single-responsibility principle** [here](https://dev.to/abrardev99/becoming-a-better-laravel-developer-by-using-the-solid-design-principles-part-1-6f9)

Today, we will discuss the second letter of **SOLID**   which is **O - Open-closed principle**. 

## What is O - Open-closed principle

According to the official definition 
> software entities should be open for extension, but closed for modification. 

Entities can be classes, modules, functions, etc. The definition meaning that extends functionality by adding new code instead of changing existing code. 
It is quite confusing to understand by title. So let's see it with examples in Laravel. 

Let's say we have an e-commerce system that involves payments. So, we have `PaymentController` and in that controller, we have `pay` method which has two payment methods for now 1) Credit Card 2) Paypal and looks like below:  
`PaymentController.php`

```
public function pay(Request $request)
    {
        $payment = new Payment();
        if($type == 'credit'){
            // do credit card payments
            $payment->paymentWithCreditCard();
        }else {
            //do paypal payments
            $payment->paymentWithPaypal();
        }
    }
```

and our `Payment` class looks like this: 
`Payment.php`
```
class Payment
{

    public function paymentWithCreditCard()
    {
        // logic for credit card payments 
    }

    public function paymentWithPaypal()
    {
        // logic for paypal payments
    }
}
```

What happens when we want to **add a new payment method** let's say **wire transfer**

In `pay` method we add a new if condition and call an appropriate method from the `Payment` class.
So the `pay` method looks like below:
`PaymentController.php`

```
public function pay(Request $request)
    {
        $payment = new Payment();
        if($type == 'credit'){
            // do credit card payments
            $payment->paymentWithCreditCard();
        }else if($type == 'paypal') {
            //do paypal payments
            $payment->paymentWithPaypal();
        }
        else {
            //do wire transfer payments
            $payment->paymentWithWiretransfer();
        }
    }
```

and modifying the `Payment` class: 
`Payment.php`

```
class Payment
{

    public function paymentWithCreditCard()
    {
        // logic for credit card payments
    }

    public function paymentWithPaypal()
    {
        // logic for paypal payments
    }

    public function paymentWithWiretransfer()
    {
        // logic for wire transfer payments
    }
}
```

So what will happen next **What if we have another payment method called Cash on Delivery, we have added another `if` and then a new method in the `Payment` class. Another payment method comes called Coupon Payment and we are again modifying classes. Remember what does this principle says, Open for extension but close for modifications. so we are breaking this principle here.**
So, how to fix it, let's apply Open Close Principle here. 

Let's make a new `interface` with a method named `pay` [read more](https://www.geeksforgeeks.org/php-interface/#:~:text=PHP%20%7C%20Ternary%20Operator-,PHP%20%7C%20Interface,the%20particular%20methods%20are%20implemented.&text=The%20interface%20contains%20no%20data%20variables.) about interfaces in PHP. 
`PayableInterface.php` 

```
interface PayableInterface
{
    public function pay();
}
```

Make a `class` for each payment method and extend it with the `PayableInterface` interface. 
`CreditCardPayment.php`

```
class CreditCardPayment implements PayableInterface
{

    public function pay()
    {
        // Implement Credit Card payment logic
    }
}
```

`PaypalPayment.php`

```
class PaypalPayment implements PayableInterface
{

    public function pay()
    {
        // Implement paypall payment logic
    }
}
```

`CreditCardPayment.php`

```
class WiretransferPayment implements PayableInterface
{

    public function pay()
    {
        // Implement Wire transfer payment logic
    }
}
```

Now, make a new class 
`PaymentFactory.php`
```
class PaymentFactory
{
    public function initializePayment($type)
    {
        if($type == 'credit'){
            // do credit card payments
            return new CreditCardPayment;
        }else if($type == 'paypal') {
            //do paypal payments
            return new PaypalPayment;
        }
        else if ($type == 'wire') {
            //do wire transfer payments
            return new WiretransferPayment;
        }
    }
}
```


and finally our `pay` method in
`PaymentController.php`. This pay method asks `PaymentFactory` todo the payments and factory handle itself everything. 

```
public function pay(Request $request)
    {
        $paymentFactory = new PaymentFactory();
        $paymentMethod = $paymentFactory->initializePayment($request->type);
        $paymentMethod->pay();
    }
```

So what will happen next **What if we have another payment method called Cash on Delivery** we will make a new `class` called `CashOnDeliveryPayment.php` and implement the same `payableInterface` which will give us `pay` method to put cash on delivery logic there. 

That's it. We solve the issue of modifying the classes now if the new payment method comes we extend functionality by adding new class instead of modifying the existing one. 

Please comment down below if you do not understand any part of the article.