Service Layer Pattern
Example that simply simulate the action of sending an email by printing text.
This shows the Service Layer Pattern clearly.
You move all email logic to a dedicated class.
Controllers stay clean, emails become testable.
-------------------------------------------------
Project Folder Structure (PSR-4 Compatible)
project/
│
├── composer.json
├── vendor/ (created after composer install)
│
├── src/
│ ├── Email/
│ │ ├── GenericEmail.php
│ │ └── EmailService.php
│ │
│ └── App.php (example controller-like file)
│
└── index.php
-------------------------------------------------
composer install
composer dump-autoload
-------------------------------------------------
Why Not a Single EmailService?
If you put everything inside EmailService (view rendering, subject, attachments),
you end up with a class that:
- Has too many responsibilities
- Is harder to test
- Becomes messy once you add more email types
- Is tightly coupled to the internal email-building logic
Example:
What happens when you need a weekly report email, a password reset email, etc.?
If all email-building logic lives inside EmailService,
that class becomes a "God Class" quickly.
Generic Class
namespace App\Email;
class GenericEmail
{
public function __construct(
public string $to,
public string $subject,
public string $body,
public array $attachments) {}
public function build(): object
{
$mail = [
"to" => $this->to,
"subject" => $this->subject,
"body" => $this->body,
"attachments" => $this->attachments ?? [],
];
foreach($this->attachments as $path) {
$this->attach($path);
}
return (object) $mail;
}
public function attach(string $filePath): self
{
$this->attachments[] = $filePath;
return $this;
}
}
Service
namespace App\Email;
class EmailService
{
public function send(GenericEmail $genericEmail): void
{
$email = $genericEmail->build();
echo "\n EMAIL SENT / Subject: {$email->subject} ";
foreach ($email->attachments as $path) {
echo " / $path";
}
}
}
Application
namespace App;
use App\Email\EmailService;
use App\Email\GenericEmail;
class App
{
public function run(): void
{
$service = new EmailService();
$service->send(new GenericEmail(
"john@example.com",
"Welcome",
"Hello John, welcome!",
["welcome_guide.pdf"]
));
$service->send(new GenericEmail(
"john@example.com",
"Reset Password",
"Click this to reset password.",
["instructions.txt"]
));
}
}
Usage Example
require __DIR__ . '/vendor/autoload.php';
$app = new App\App();
$app->run();