@dmytro_shved When I’ve implemented this in the past, I’ve created a SubscriberService interface, and then classes that implement that interface, such as MailchimpSubscriberService. This makes it easier to swap out with say, a Campaign Monitor implementation.
The implementation would look something like this:
class MailchimpSubscriberService implements SubscriberService
{
protected ApiClient $client;
public function __construct(ApiClient $client)
{
$this->client = $client;
}
public function subscribe(string $listId, string $email): bool
{
$hash = md5(strtolower($email));
$this->client->lists->setListMember($listId, $hash, [
'email_address' => $email,
'status_if_new' => 'pending',
]);
return true;
}
}
You can register the Mailchimp API client with the service container, so that you don‘t have to manually instantiate it and manually pass configuration values, each and every time you want to use it throughout your application:
class AppServiceProvider extends ServiceProvider
{
public function register(): void
{
$this->app->singleton(ApiClient::class, function () {
$client = new ApiClient();
return $client->setConfig([
'apiKey' => $this->app->make('config')->get('services.mailchimp.api_key'),
'server' => $this->app->make('config')->get('services.mailchimp.server_prefix'),
]);
});
}
}
You should also bind your implementation to the interface in a service provider:
$this->app->singleton(SubscriptionService::class, MailchimpSubscriptionService::class);
Laravel will now resolve the bound implementation if you type-hint the interface (such as a controller). If it resolves the Mailchimp implementation, it will also see that it has a dependency on the ApiClient class, so will then resolve that via the container and inject it. That means using it in a controller looks like this:
class NewsletterSubscriptionController extends Controller
{
protected SubscriptionService $subscriptionService;
public function __construct(SubscriptionService $subscriptionService)
{
$this->subscriptionService = $subscriptionService;
}
public function store(StoreSubscriptionRequest $request)
{
$this->subscriptionService->subscribe($request->input('email'));
// Return response...
}
}
You’re now relying only on interfaces, and no longer having to manually instantiate API clients or other classes.
I’ve created a Gist with an example implementation: https://gist.github.com/martinbean/be48e0ec37ba59a05e52b936a5721023