Yapısal Mühendislik ve Tasarım
Laravel'deki Builder Desen ile Esnek bir E-posta Kampanyası Sistemi tasarlayın
Table of Contents
Modern pazarlama, izleyici segmentlerine hızla adapte olan e-posta kampanyalarını, A/B testleri ve dinamik içerik talep ediyor. Katı, monolithic uygulama hızla, temel mantığıyla bileşenleri değiştirmenize izin veriyor. Laravel, temel mantığıyla, doğru tasarım modelini seçmede gerçek anahtar, ancak doğru tasarım kalıbı seçmekte.The Builder Pattern hızla karmaşık e-posta nesneleri adımını inşa etmek için güçlü bir çözüm olarak duruyor.
Bu kapsamlı kılavuzda, Laravel'deki herhangi bir e-posta kampanyası sistemini mimar olarak nasıl öğreneceksiniz - teoriyi kıracağız, Laravel'in posta ve kuyruk sistemleri ile entegrasyon.Sonunda, herhangi bir e-posta kampanyası oluşturmak için bir e-posta kampanyasına yaklaşımınız olacak - en az kod duplikasyonuyla.
Builder Desen Nedir?
Builder Desen, son gösteriminden karmaşık bir nesnenin inşasını ayıran bir yaratım tasarım modelidir. büyük bir inşaat veya fabrika yöntemleri ile bir takım fabrika yöntemiyle bir nesne oluşturmak yerine, bina işlemini özel bir yönetmen ve inşaat derslerine deletiriyorsunuz. yönetmen orkestralar her bir inşaatçının bileşenlerinin belirli bir şekilde nasıl şekillendirdiğini bilir.
Bu model birçok seçenek gerektirdiğinde, birden fazla konfigürasyon adımına sahiptir veya farklı nesneler üretmeniz gerektiğinde benzer nesnelere benzer bir şekilde ifade verebilir. e-posta kampanyaları için, “object” e-posta mesajıdır - konuyla tamam, vücut, ekler, alıcılar, üst düzeyler ve metadata. Her kampanya türü (promotional, işlemsel, olay-trigger) ortak bir temel paylaşabilir, ancak bilgi, veya içerikli bloklar.
Fabrika Deseninden Nasıl Differs
Fabrika Deseni tek bir çağrıda nesneler yaratmaya odaklanırken, Builder Kalıp kontrollü, parçalı inşaat sürecine izin verir. Fabrikalar, Yaratılış mantığı basit olduğunda idealdir; inşaatçılar, parçaları kontrol etmeniz gerektiğinde daha iyidir. e-posta sistemlerinde, genellikle vücut şablonunu değiştirir veya farklı teslimat önceliklerini ayarlar.The Builder size tek bir fabrika sınıfı olmadan kontrol verir.
Laravel Çevrenizi Ayarlayın
Koda dalmadan önce, bir Laravel uygulamanız ( 9 veya daha sonra) varsayılan posta yapılandırması ile ilgili olarak, kampanyalar, aboneler ve şablonlar için gerekli veritabanı masalarına sahip olduğunuzu varsayacağız - ancak bu makale için, inşaatçı mantığının kendisi ile birlikte takip edebilirsiniz.
composer create-project laravel/laravel email-campaign-builder
Sonraki, posta sürücünüzü 03.D.T.'de yapılandırın (örneğin, [[D.D.D.) Ayrıca Laravel'in 03.03.2012'yi kullanacağız.
Builder Kalıplarının Temelleri
Dört temel bileşeni uygulayacağız:
- [FONT:0)Ürün[DÜT:1) - Son e-posta nesnesi (ortalama), aENFLT:6) değeri nesnesi veya Laravel'nin İLDİĞİ 7'nin uzatması.
- [FONT:0)Builder Interface[[Dönetici: 1 ) – E-postanın her bir parçası için Declares yöntemleri: konu, vücut, alıcılar, ekler, başlıklar, vb.
- [[Döneticiler[[Döneticiler)[[Döneticiler:0)Concrete Builders[[Döneticiler: Her biri belirli bir e-posta türü için arayüz uygular (Promotional, Transactional, Welcome serisi).
- [FONT:0)Yönetici) – Komiser, aynı inşaatın birden çok e-posta üretmesini kullanarak aynı inşaat adımlarını mavi bir baskıdan üretmiştir.
Adım 1: E-posta Mesaj Ürününü Tanımlayın
Tüm e-posta verilerini tutmak için basit bir değer nesnesi oluşturacağız. Bu, inşaatçı kodumuzu temiz ve test edilebilir tutar.
<?php
namespace App\Values;
class EmailMessage
{
public string $subject;
public string $body;
public string $mimeType = 'text/html'; // or text/plain
public array $recipients = [];
public array $ccRecipients = [];
public array $bccRecipients = [];
public array $attachments = [];
public array $headers = [];
public ?string $fromAddress = null;
public ?string $fromName = null;
public function toArray(): array
{
return [
'subject' => $this->subject,
'body' => $this->body,
'mimeType' => $this->mimeType,
'recipients' => $this->recipients,
'cc' => $this->ccRecipients,
'bcc' => $this->bccRecipients,
'attachments' => $this->attachments,
'headers' => $this->headers,
'from' => ['address' => $this->fromAddress, 'name' => $this->fromName],
];
}
}
Adım 2: Builder Interface
arayüz, herhangi bir e-posta değişkeni oluşturmak için sözleşmeyi tanımlar.
<?php
namespace App\Builders\Contracts;
use App\Values\EmailMessage;
interface EmailBuilderContract
{
public function setSubject(string $subject): self;
public function setBody(string $body, string $mimeType = 'text/html'): self;
public function addRecipient(string $email, ?string $name = null): self;
public function addCc(string $email, ?string $name = null): self;
public function addBcc(string $email, ?string $name = null): self;
public function addAttachment(string $filePath, ?string $name = null): self;
public function addHeader(string $key, string $value): self;
public function setFrom(string $address, ?string $name = null): self;
public function getEmail(): EmailMessage;
public function reset(): void;
}
Adım 3: Promosyon E-postaları için Beton Builder
Promosyonlar için e-postayı tertemiz bir inşaatçı yapalım – piksel, sosyal paylaşım bağlantıları ve standart bir giriş ayaklayıcısı.
<?php
namespace App\Builders;
use App\Builders\Contracts\EmailBuilderContract;
use App\Values\EmailMessage;
class PromotionalEmailBuilder implements EmailBuilderContract
{
private EmailMessage $email;
public function __construct()
{
$this->reset();
}
public function setSubject(string $subject): self
{
$this->email->subject = '[Promo] ' . $subject;
return $this;
}
public function setBody(string $body, string $mimeType = 'text/html'): self
{
// Wrap body with promotional header/footer
$this->email->body = $this->wrapBody($body);
$this->email->mimeType = $mimeType;
return $this;
}
private function wrapBody(string $body): string
{
return "<div style=\"background:#f5f5f5; padding:20px;\">
<div style=\"max-width:600px; margin:auto;\">
$body
<hr>
<p style=\"font-size:12px; color:#888;\">
You received this because you opted in.
<a href=\"{{unsubscribe_url}}\">Unsubscribe</a>
</p>
</div>
</div>";
}
public function addRecipient(string $email, ?string $name = null): self
{
$this->email->recipients[] = compact('email', 'name');
return $this;
}
public function addCc(string $email, ?string $name = null): self
{
$this->email->ccRecipients[] = compact('email', 'name');
return $this;
}
public function addBcc(string $email, ?string $name = null): self
{
$this->email->bccRecipients[] = compact('email', 'name');
return $this;
}
public function addAttachment(string $filePath, ?string $name = null): self
{
$this->email->attachments[] = ['path' => $filePath, 'name' => $name];
return $this;
}
public function addHeader(string $key, string $value): self
{
$this->email->headers[$key] = $value;
return $this;
}
public function setFrom(string $address, ?string $name = null): self
{
$this->email->fromAddress = $address;
$this->email->fromName = $name;
return $this;
}
public function getEmail(): EmailMessage
{
$built = clone $this->email;
$this->reset();
return $built;
}
public function reset(): void
{
$this->email = new EmailMessage();
}
}
Adım 4: İşlemsel Builder Örnek
Bir işlemsel e-posta (örneğin, sipariş onayı) farklı bir sarmalayıcıya ihtiyaç duyar - minimum markalama, öncelik başlıkları ve hiçbir girişsiz ayaklama.
<?php
namespace App\Builders;
class TransactionalEmailBuilder implements EmailBuilderContract
{
private EmailMessage $email;
// ... same structure, but setSubject does not prepend prefix
// and wrapBody() uses a simple layout with order details
// getEmail() resets the builder
}
Yönetmen: Build the Build
Yönetmen bir inşaatçı örneği alır ve belirli bir sırayla adımlarını çağırır. Bu, “bir abone için bir kampanya e-postası oluşturma gibi standart dizileri tanımlayabilirsiniz.”
<?php
namespace App\Builders;
use App\Builders\Contracts\EmailBuilderContract;
use App\Models\User;
class CampaignDirector
{
public function __construct(private EmailBuilderContract $builder) {}
public function buildPromotionalCampaign(User $user, string $subject, string $body): EmailMessage
{
return $this->builder
->setFrom('[email protected]', 'Marketing Team')
->setSubject($subject)
->addRecipient($user->email, $user->name)
->addHeader('X-Campaign-Id', $campaignId)
->setBody($body)
->getEmail();
}
public function buildTransactionalOrderConfirmation(Order $order): EmailMessage
{
// Switch builder if needed, or use a different director method
// (In practice, you'd instantiate a TransactionalEmailBuilder)
$this->builder = new TransactionalEmailBuilder();
$body = view('emails.order-confirmation', compact('order'))->render();
return $this->builder
->setFrom('[email protected]', 'Order System')
->setSubject('Order Confirmation #' . $order->id)
->addRecipient($order->user->email, $order->user->name)
->setBody($body)
->addHeader('X-Transaction-Id', $order->transaction_id)
->addAttachment(storage_path('invoices/' . $order->invoice_file))
->getEmail();
}
}
Bir yönetmenin kullanılması inşaat mantığı merkezileşmiştir. Daha sonra birİLFLT:13 eklemek gerekir, sadece inşaatçılara dokunmadan yönetmeni genişletirsiniz.
Laravel Mail ile Bütünleşme
Bir kere bir değer nesnesi varsa, bunu göndermeniz gerekir.Adaying theETHD:15) ve Laravel'in yerleşik posta sistemini kullanarak onu kullanan özel bir Mailable oluşturun.
<?php
namespace App\Mail;
use App\Values\EmailMessage;
use Illuminate\Bus\Queueable;
use Illuminate\Mail\Mailable;
use Illuminate\Mail\Mailables\Attachment;
use Illuminate\Mail\Mailables\Content;
use Illuminate\Mail\Mailables\Envelope;
use Illuminate\Queue\SerializesModels;
class CampaignMail extends Mailable
{
use Queueable, SerializesModels;
public function __construct(public EmailMessage $emailMessage) {}
public function envelope(): Envelope
{
return new Envelope(
from: $this->emailMessage->fromAddress
? new Address($this->emailMessage->fromAddress, $this->emailMessage->fromName)
: null,
subject: $this->emailMessage->subject,
cc: $this->emailMessage->ccRecipients,
bcc: $this->emailMessage->bccRecipients,
headers: $this->emailMessage->headers,
);
}
public function content(): Content
{
return new Content(
htmlString: $this->emailMessage->body,
);
}
public function attachments(): array
{
return array_map(function ($attach) {
return Attachment::fromPath($attach['path'])
->as($attach['name'] ?? null);
}, $this->emailMessage->attachments);
}
}
Artık inşaatçıyı kullanarak herhangi bir kontrolör veya işten e-posta gönderebilirsiniz:
use App\Builders\PromotionalEmailBuilder;
use App\Builders\CampaignDirector;
use App\Mail\CampaignMail;
use Illuminate\Support\Facades\Mail;
$builder = new PromotionalEmailBuilder();
$director = new CampaignDirector($builder);
$emailMessage = $director->buildPromotionalCampaign($user, 'Summer Sale', $htmlContent);
Mail::to($user->email)->send(new CampaignMail($emailMessage));
Scalability için Queue'i kovalamak
E-posta kampanyası sistemleri, her alıcı için inşaatçıyı kullanan bir takımda mükemmel bir maç.
<?php
namespace App\Jobs;
use App\Builders\Contracts\EmailBuilderContract;
use App\Builders\CampaignDirector;
use App\Mail\CampaignMail;
use App\Models\Subscriber;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
use Illuminate\Queue\SerializesModels;
use Illuminate\Support\Facades\Mail;
class SendCampaignEmail implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
public function __construct(
private Subscriber $subscriber,
private string $subject,
private string $body,
private string $builderClass // class-string
) {}
public function handle(): void
{
$builder = app($this->builderClass);
$director = new CampaignDirector($builder);
$emailMessage = $director->buildPromotionalCampaign(
$this->subscriber->user,
$this->subject,
$this->body
);
Mail::to($this->subscriber->email)
->send(new CampaignMail($emailMessage));
}
}
İşi bir döngüde her bir abone için (veya daha iyi, ESFLT:19) başarılı / güvenli gönderimleri yönetmek için kullanın.
Blades ile Dinamik Şablonlar Ekleyin
Geliştiricilerdeki HTML'yi zorlaştırmak ideal değildir. Bunun yerine, mücevher görüşlerini vücudunuz olarak kabul edebilir.Yapıcınız bir görüntü adı ve veri serisini kabul edebilir, sonra [[Dönemli:) içinde bulunan kalıplarınızı ayrı tutar ve tasarımcılar için düzenlemenizi sağlar.
public function setBody(string $viewName, array $data = [], string $mimeType = 'text/html'): self
{
$rendered = view($viewName, $data)->render();
$this->email->body = $this->wrapBody($rendered);
$this->email->mimeType = $mimeType;
return $this;
}
Şimdi sen de arayabilirsiniz.
Gerçek Dünya Kampanyalarında Faydaları
- [FONT:0] · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · · ·
- [FONT:0)Testability) - Her inşaatçıyı, özelliklerini yeniden kullanarak yeniden test edebilirsiniz.
- [FONT:0]Easier A/B Test[DÜT:1] – Swap inşaat süreci değişken bir grup için inşaat süreci değişmeden kalır.
- [FONT:0]Sürücük izler[Döneticiler[Döneticiler)[Döneticiler)[değiştir | kaynağı değiştir]
- [FONT:0) Dış hizmetlerle ilgili olarak () - Mailgun, SendGrid veya SparkPost gibi hizmetler için ücret yüklerini bir araya getirmek için inşaatçıyı kullanın.
En İyi Uygulamalar ve Ortak Pitfalls
Keep Builders Stateless Nerede Mümkün
[FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=STRNT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT=FONT
Basit E-postalar için fazla mühendislik yapma
Uygulamanız sadece bir tür e-posta gönderirse, Builder Kalıp aşırı olabilir. Farklı bileşenlerle en az üç farklı e-posta türü olduğunda parlar.
Builders için Bağlanma Enjeksiyonu
İnşaatçılara hizmet konteynerinde kayıt olun, böylece bağımlılıklara (kullanıcıları veya izleme hizmetleri gibi) kolayca enjekte edebilirsiniz.
Recipients Sayısını Düşünmek
Yapım, tek bir kutuda binlerce alıcı toplamamalıdır:) - bu, gigabaytları hafızaya yükleyecek veya bir e-postayı satın almalı veya toplu API'leri kullanmalıdır (Mailgun'surFLT:30).
Daha Fazla Gelişmiş
Bir Eloquent modeli, inşaatçı sınıfı, şablon ve varsayılan parametreler sunan bir Eloquent modeli eklemeyi düşünün. Sonra bir programcı iş mavi baskıları okur ve yönetmenin tüm aktif aboneler için sıra e-postalarını kullanıyor.
Ayrıca, küresel kuralları geçerli olan (her zaman bir iptal bağlantı eklemek gibi) belirli inşaatçıya dalmadan önce bir başka ayrılık katmanını da ortaya çıkarabilirsiniz.
Dış Kaynaklar
- [FONT:0)Builder Desen - Refaksiyon Guru) (excellent görsel açıklama)
- [FONT:0)Laravel Mail Dokümantasyon[Dönemli sınıf referansı için]
- [FONT:0)Laravel Queues[[Dönetici: 1 )
Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç Sonuç
Esnek bir e-posta kampanyası sistemi tasarlamak büyük bir çerçeve gerektirmez. Laravel'deki Builder Desen ile, e-posta inşaatında kesin kontrol edin, pazarlama ihtiyaçlarınızı değiştirmek için kodbase adapte edilebilir hale getirin. Kampanyalarınızı nasıl (önetici) terk etmek için nasıl (yönetici) etkinleştirin.