Skip to content

Commit d199301

Browse files
committed
ISSUE-345: refactor
1 parent 536fff8 commit d199301

File tree

10 files changed

+202
-70
lines changed

10 files changed

+202
-70
lines changed

.env.example

Lines changed: 0 additions & 27 deletions
This file was deleted.

composer.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,9 @@
6464
"symfony/amazon-mailer": "^6.4",
6565
"symfony/mailchimp-mailer": "^6.4",
6666
"symfony/sendgrid-mailer": "^6.4",
67-
"symfony/dotenv": "^6.4"
67+
"symfony/dotenv": "^6.4",
68+
"symfony/twig-bundle": "^6.4",
69+
"symfony/messenger": "^6.4"
6870
},
6971
"require-dev": {
7072
"phpunit/phpunit": "^9.5",

config/PHPMD/rules.xml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@
5151
<!-- rules from the "naming" rule set -->
5252
<rule ref="rulesets/naming.xml/ShortVariable">
5353
<properties>
54-
<property name="exceptions" value="id,ip"/>
54+
<property name="exceptions" value="id,ip,cc"/>
5555
</properties>
5656
</rule>
5757
<rule ref="rulesets/naming.xml/LongVariable">

config/config.yml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,3 +39,5 @@ framework:
3939
serializer:
4040
enabled: true
4141
enable_attributes: true
42+
mailer:
43+
dsn: '%app.mailer_dsn%'

config/parameters.yml.dist

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,3 +25,8 @@ parameters:
2525
# A secret key that's used to generate certain security-related tokens
2626
secret: '%%env(PHPLIST_SECRET)%%'
2727
env(PHPLIST_SECRET): %1$s
28+
29+
app.mailer_from: '%env(MAILER_FROM)%'
30+
env(MAILER_FROM): '[email protected]'
31+
app.mailer_dsn: '%env(MAILER_DSN)%'
32+
env(MAILER_DSN): 'smtp://username:[email protected]:2525'

config/services/commands.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
services:
2+
_defaults:
3+
autowire: true
4+
autoconfigure: true
5+
public: false
6+
7+
PhpList\Core\Domain\Messaging\Command\:
8+
resource: '../../src/Domain/Messaging/Command'
9+
tags: ['console.command']
10+

config/services/managers.yml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,3 +61,9 @@ services:
6161
autowire: true
6262
autoconfigure: true
6363
public: true
64+
65+
PhpList\Core\Domain\Messaging\Service\EmailService:
66+
autowire: true
67+
autoconfigure: true
68+
arguments:
69+
$defaultFromEmail: '%app.mailer_from%'

src/Core/Bootstrap.php

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
use Doctrine\ORM\EntityManagerInterface;
88
use Exception;
99
use RuntimeException;
10-
use Symfony\Component\Dotenv\Dotenv;
1110
use Symfony\Component\ErrorHandler\ErrorHandler;
1211
use Symfony\Component\DependencyInjection\ContainerInterface;
1312
use Symfony\Component\HttpFoundation\Request;
@@ -36,7 +35,6 @@ class Bootstrap
3635
private ?ApplicationKernel $applicationKernel = null;
3736
private ApplicationStructure $applicationStructure;
3837
private ErrorHandler $errorHandler;
39-
private bool $envLoaded = false;
4038

4139
/**
4240
* Protected constructor to avoid direct instantiation of this class.
@@ -47,33 +45,6 @@ protected function __construct()
4745
{
4846
$this->applicationStructure = new ApplicationStructure();
4947
$this->errorHandler = new ErrorHandler();
50-
$this->loadEnvironmentVariables();
51-
}
52-
53-
/**
54-
* Loads environment variables from .env files.
55-
*
56-
* @return void fluent interface
57-
*/
58-
private function loadEnvironmentVariables(): void
59-
{
60-
if ($this->envLoaded) {
61-
return;
62-
}
63-
64-
$dotenv = new Dotenv();
65-
$rootDir = $this->getApplicationRoot();
66-
67-
if (file_exists($rootDir . '/.env')) {
68-
$dotenv->load($rootDir . '/.env');
69-
70-
if (file_exists($rootDir . '/.env.local')) {
71-
$dotenv->load($rootDir . '/.env.local');
72-
}
73-
74-
$this->envLoaded = true;
75-
}
76-
7748
}
7849

7950
/**
@@ -118,10 +89,6 @@ public static function purgeInstance(): void
11889
*/
11990
public function setEnvironment(string $environment): Bootstrap
12091
{
121-
if ($environment === Environment::DEFAULT_ENVIRONMENT && isset($_ENV['APP_ENV'])) {
122-
$environment = $_ENV['APP_ENV'];
123-
}
124-
12592
Environment::validateEnvironment($environment);
12693
$this->environment = $environment;
12794

@@ -135,19 +102,11 @@ public function getEnvironment(): string
135102

136103
private function isSymfonyDebugModeEnabled(): bool
137104
{
138-
if (isset($_ENV['APP_DEBUG'])) {
139-
return $_ENV['APP_DEBUG'] === '1' || $_ENV['APP_DEBUG'] === 'true';
140-
}
141-
142105
return $this->environment !== Environment::PRODUCTION;
143106
}
144107

145108
private function isDebugEnabled(): bool
146109
{
147-
if (isset($_ENV['APP_DEBUG'])) {
148-
return $_ENV['APP_DEBUG'] === '1' || $_ENV['APP_DEBUG'] === 'true';
149-
}
150-
151110
return $this->environment !== Environment::PRODUCTION;
152111
}
153112

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Messaging\Command;
6+
7+
use Exception;
8+
use PhpList\Core\Domain\Messaging\Model\Dto\EmailMessage;
9+
use PhpList\Core\Domain\Messaging\Service\EmailService;
10+
use Symfony\Component\Console\Command\Command;
11+
use Symfony\Component\Console\Input\InputArgument;
12+
use Symfony\Component\Console\Input\InputInterface;
13+
use Symfony\Component\Console\Output\OutputInterface;
14+
use Symfony\Component\Mime\Address;
15+
use Symfony\Component\Mime\Email;
16+
17+
class SendTestEmailCommand extends Command
18+
{
19+
protected static $defaultName = 'app:send-test-email';
20+
protected static $defaultDescription = 'Send a test email to verify email configuration';
21+
22+
private EmailService $emailService;
23+
24+
public function __construct(EmailService $emailService)
25+
{
26+
parent::__construct();
27+
$this->emailService = $emailService;
28+
}
29+
30+
protected function configure(): void
31+
{
32+
$this
33+
->setDescription(self::$defaultDescription)
34+
->addArgument('recipient', InputArgument::OPTIONAL, 'Recipient email address');
35+
}
36+
37+
protected function execute(InputInterface $input, OutputInterface $output): int
38+
{
39+
$recipient = $input->getArgument('recipient');
40+
if (!$recipient) {
41+
$output->writeln('Recipient email address not provided');
42+
43+
return Command::FAILURE;
44+
}
45+
46+
if (!filter_var($recipient, FILTER_VALIDATE_EMAIL)) {
47+
$output->writeln('Invalid email address: ' . $recipient);
48+
49+
return Command::FAILURE;
50+
}
51+
52+
try {
53+
$output->writeln('Sending test email to ' . $recipient);
54+
55+
$email = (new Email())
56+
->from(new Address('[email protected]', 'Admin Team'))
57+
->to($recipient)
58+
->subject('Test Email from phpList')
59+
->text('This is a test email sent from phpList Email Service.')
60+
->html('<h1>Test</h1><p>This is a <strong>test email</strong> sent from phpList Email Service</p>');
61+
62+
$this->emailService->sendEmail($email);
63+
$output->writeln('Test email sent successfully!');
64+
65+
return Command::SUCCESS;
66+
} catch (Exception $e) {
67+
$output->writeln('Failed to send test email: ' . $e->getMessage());
68+
69+
return Command::FAILURE;
70+
}
71+
}
72+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
<?php
2+
3+
declare(strict_types=1);
4+
5+
namespace PhpList\Core\Domain\Messaging\Service;
6+
7+
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
8+
use Symfony\Component\Mailer\MailerInterface;
9+
use Symfony\Component\Mime\Email;
10+
use Symfony\Component\Mime\Address;
11+
12+
class EmailService
13+
{
14+
private MailerInterface $mailer;
15+
private string $defaultFromEmail;
16+
17+
public function __construct(MailerInterface $mailer, string $defaultFromEmail)
18+
{
19+
$this->mailer = $mailer;
20+
$this->defaultFromEmail = $defaultFromEmail;
21+
}
22+
23+
/**
24+
* Send a simple email
25+
*
26+
* @param Email $email
27+
* @param array $cc
28+
* @param array $bcc
29+
* @param array $replyTo
30+
* @param array $attachments
31+
* @return void
32+
* @throws TransportExceptionInterface
33+
*/
34+
public function sendEmail(
35+
Email $email,
36+
array $cc = [],
37+
array $bcc = [],
38+
array $replyTo = [],
39+
array $attachments = []
40+
): void {
41+
if (count($email->getFrom()) === 0) {
42+
$email->from($this->defaultFromEmail);
43+
}
44+
45+
foreach ($cc as $ccAddress) {
46+
$email->addCc($ccAddress);
47+
}
48+
49+
foreach ($bcc as $bccAddress) {
50+
$email->addBcc($bccAddress);
51+
}
52+
53+
foreach ($replyTo as $replyToAddress) {
54+
$email->addReplyTo($replyToAddress);
55+
}
56+
57+
foreach ($attachments as $attachment) {
58+
$email->attachFromPath($attachment);
59+
}
60+
61+
$this->mailer->send($email);
62+
}
63+
64+
/**
65+
* Email multiple recipients
66+
*
67+
* @param array $toAddresses Array of recipient email addresses
68+
* @param string $subject Email subject
69+
* @param string $text Plain text content
70+
* @param string $html HTML content (optional)
71+
* @param string|null $from Sender email address (optional, uses default if not provided)
72+
* @param string|null $fromName Sender name (optional)
73+
* @param array $attachments Array of file paths to attach (optional)
74+
*
75+
* @return void
76+
* @throws TransportExceptionInterface
77+
*/
78+
public function sendBulkEmail(
79+
array $toAddresses,
80+
string $subject,
81+
string $text,
82+
string $html = '',
83+
?string $from = null,
84+
?string $fromName = null,
85+
array $attachments = []
86+
): void {
87+
$baseEmail = (new Email())
88+
->subject($subject)
89+
->text($text)
90+
->html($html);
91+
92+
if ($from) {
93+
$baseEmail->from($fromName ? new Address($from, $fromName) : $from);
94+
}
95+
96+
foreach ($toAddresses as $recipient) {
97+
$email = clone $baseEmail;
98+
$email->to($recipient);
99+
100+
$this->sendEmail($email, [], [], [], $attachments);
101+
}
102+
}
103+
}

0 commit comments

Comments
 (0)