Padrão de projeto Adapter em PHP 
Tags: braziliandevs, php, webdev, oop
Published: 2021-12-06 20:38:40

Os usuários e usuárias estão amando sua aplicação e você quer dar a eles mais alegria. O que poderia trazer mais felicidade do que notificações por email?

![Alguém sentindo alegria](https://media.giphy.com/media/3NtY188QaxDdC/giphy.gif)

## Vamos dar boas vindas!
Nós queremos que nossos usuários e usuárias se sintam bem depois de se cadastrarem na nossa aplicação, então por que não enviar um email de boas vindas? Você já conhece um serviço de email confiável que tem um SDK fácil de instalar utilizando Composer. Tudo parece estar correndo bem até agora.

Infelizmente, ao integrar o SDK você nota que as classes não se encaixam muito bem. `SignUpService` contém apenas o destinatário e o conteúdo, enquanto `ThirdPartyEmailClient` espera parâmetros de configuração.

Nosso SDK hipotético possui a seguinte estrutura:
```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);
    }
}
```
![Diagrama das classes SignUpService e ThirdPartyEmailClient](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l175txvyywsa6dcn5jwl.png)

## Faça funcionar
Se `ThirdPartyEmailClient` está pedindo por uma `apiKey` e `region`, vamos satisfazer seus pedidos. Nós podemos simplesmente injetar os dois parâmetros na classe `SignUpService`, ou mesmo colocando eles diretamente no código (_hardcoding_). Não seria um problema até você precisar depois enviar um email após o usuário atualizar o seu perfil, implementado em outra classe chamada `ProfileService`.

Bom, por enquanto você só está preocupado em implementar a funcionalidade corretamente porque você é um bom profissional e quer entregar o prometido. A solução por agora é copiar e colar os parâmetros na classe `SignUpService`. Bom trabalho!

## Algo parece errado
![Gif de alguém com insônia](https://media.giphy.com/media/xUOrwihszfWZgSIHJK/giphy.gif)

Naquela noite você não conseguiu dormir por causa daquele código duplicado. A `apiKey` também está exposta em todos os lugares. Como resolver esse problema?

## Faça funcionar melhor
Eis então que você se lembra do padrão `Adapter`. Ele serve para integrar classes que tem interfaces incompatíveis. O primeiro passo é criar a interface esperada pelo cliente:
```php
interface EmailSenderAdapter
{
    public function sendEmail(string $recipient, string $content): void;
}
```

Agora você só precisa colocar `ThirdPartyEmailClient` numa classe que implementa a interface anterior:
```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` agora está feliz porque tem um amigo que entende sua linguagem.


![Diagrama após a implementação do adapter](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/1208etxewd462mx89zr9.png)

E para melhorar mais ainda, você decide adicionar um teste unitário!

## Testando
```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');
}
```

## Você conseguiu!
![Programador feliz](https://media.giphy.com/media/KAqM1EwUVeTGWbNwfZ/giphy.gif)

Suas classes estão bem integradas, testadas e se um dia você precisar alterar o provedor de email, seria só necessário criar uma implementação nova de `EmailSenderAdapter`, e então a interface antiga pode ser trocada pela nova. Parabéns.

[Código no Github](github.com/fabiothiroki/php-design-patterns).
{% github github.com/fabiothiroki/php-design-patterns %}