PHP Design Patterns - Adapter 
Tags: php, webdev, tutorial, oop
Published: 2021-11-02 18:38:36

Users are loving your application and you want to give them more joy. What could bring them more happiness than email notifications?

![Someone feeling joy](https://media.giphy.com/media/3NtY188QaxDdC/giphy.gif)

## Let's welcome our users!
We want our users to feel good after signing up in our application, so why not send an welcome email? You already know a reliable email service provider that has a SDK you can install using Composer, so everything seems lovely so far.

Unfortunately, when integrating the SDK you notice the classes doesn't fit very well. `SignUpService` only has the recipient email and the content, and `ThirdPartyEmailClient` expects configuration parameters.

Our hypotethical SDK has the following structure:
```php
class ThirdPartyEmailClient
{
    public function __construct(
        private string $apiKey,
        private string $region,
    ) {
    }

    public function sendEmail(
        string $recipient,
        string $content,
    ): void {
        echo sprintf("Using apiKey %s and region %s", $this->apiKey, $this->region);
        echo sprintf("Sending email to %s and content %s", $recipient, $content);
    }
}
```

![Diagram of interaction between SignUpService and ThirdPartyEmailClient](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l175txvyywsa6dcn5jwl.png)

## Make it work
If `ThirdPartyEmailClient` is asking for `apiKey` and `region`, let's fullfil its wishes. We could simply do it by injecting both parameters on `SignUpService`, or even by hardcoding them. It wouldn't be a problem until you need to send an email after user updated his profile that is implemeted on `ProfileService` class.

Well, you're just figuring out how to make it work because you're a good professional and want to get things done, then you just copy and paste the hardcoded parameters from `SignUpService`. Good job!

## Something feels wrong
![Gif of someone with insomnia](https://media.giphy.com/media/xUOrwihszfWZgSIHJK/giphy.gif)

That night you couldn't sleep because of that code duplication. You're also exposing the `apiKey` everywhere. How to solve this problem?

## Make it right
Then you remember of this pattern called `Adapter`. It is supposed to make classes that have incompatible interfaces work together. First step is creating the interface expected by client:
```php
interface EmailSenderAdapter
{
    public function sendEmail(string $recipient, string $content): void;
}
```

Now you just need to wrap `ThirdPartyEmailClient` in a new class that implements the previous interface:
```php
final class ThirdPartyEmailSenderAdapter implements EmailSenderAdapter
{
    public function __construct(private ThirdPartyEmailClient $emailClient)
    {
    }

    public function sendEmail(string $recipient, string $content): void
    {
        $this->emailClient->sendEmail($recipient, $content);
    }
}
```
`SignUpService` is happy now because it has a friend that understands its language.

![Diagram after the adapter implementation](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1208etxewd462mx89zr9.png)

And now to make it even better, you decide to add a unit test!

## Testing
```php
public function testThirdPartyEmailSenderAdapterAdapterUsesCorrectClient(): void
{
    $emailClient = $this->createMock(ThirdPartyEmailClient::class);

    $emailAdapter = new ThirdPartyEmailSenderAdapter($emailClient);

    $emailClient->expects($this->once())
        ->method('sendEmail')
        ->with('email@email.com', 'I love design patterns');

    $emailAdapter->sendEmail(
        'email@email.com',
        'I love design patterns');
}
```
## You did it!
![Happy programmer](https://media.giphy.com/media/KAqM1EwUVeTGWbNwfZ/giphy.gif)

Your classes are seamless integrated, tested and if you need to change the email service provider you just need to wrap the new client to implement the `EmailSenderAdapter` and you can switch an old interface for the new one. Congratulations.

[Final code on Github](github.com/fabiothiroki/php-design-patterns).
{% github github.com/fabiothiroki/php-design-patterns %}