Skip to content

Commit 2ceadee

Browse files
authored
Merge pull request #359 from dotkernel/issue-358
Issue #358: Render templates separately then pass body to `MailService`
2 parents 366c769 + 51f46ee commit 2ceadee

File tree

9 files changed

+107
-60
lines changed

9 files changed

+107
-60
lines changed

src/Core/src/App/src/Entity/AbstractEntity.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,14 @@ public function getUuid(): UuidInterface
3030
return $this->uuid;
3131
}
3232

33+
/**
34+
* Override this method in soft-deletable entities
35+
*/
36+
public function isDeleted(): bool
37+
{
38+
return false;
39+
}
40+
3341
public function exchangeArray(array $array): void
3442
{
3543
foreach ($array as $property => $values) {

src/Core/src/App/src/Entity/EntityInterface.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,20 @@
44

55
namespace Core\App\Entity;
66

7+
use DateTimeImmutable;
8+
use Ramsey\Uuid\UuidInterface;
9+
710
interface EntityInterface
811
{
12+
public function getUuid(): UuidInterface;
13+
14+
public function getCreated(): ?DateTimeImmutable;
15+
16+
public function getCreatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): string;
17+
18+
public function getUpdated(): ?DateTimeImmutable;
19+
20+
public function getUpdatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): ?string;
21+
22+
public function isDeleted(): bool;
923
}

src/Core/src/App/src/Entity/RoleInterface.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,9 @@
55
namespace Core\App\Entity;
66

77
use BackedEnum;
8-
use Ramsey\Uuid\UuidInterface;
98

10-
interface RoleInterface
9+
interface RoleInterface extends EntityInterface
1110
{
12-
public function getUuid(): UuidInterface;
13-
1411
public function getName(): ?BackedEnum;
1512

1613
public function setName(BackedEnum $name): RoleInterface;

src/Core/src/App/src/Message.php

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
namespace Core\App;
66

7+
use function count;
78
use function implode;
89
use function sprintf;
910

@@ -34,18 +35,23 @@ class Message
3435
. 'you will receive an email with further instructions on resetting your account\'s password.';
3536
public const MAIL_SENT_USER_ACTIVATION = 'User activation mail has been successfully sent to "%s"';
3637
public const MISSING_CONFIG = 'Missing configuration value: "%s".';
38+
public const NOT_ACCEPTABLE = 'Not acceptable.';
3739
public const RESET_PASSWORD_EXPIRED = 'Reset password hash is invalid (expired).';
3840
public const RESET_PASSWORD_NOT_FOUND = 'Reset password request not found.';
3941
public const RESET_PASSWORD_OK = 'Password successfully modified.';
4042
public const RESET_PASSWORD_USED = 'Reset password hash is invalid (used).';
4143
public const RESET_PASSWORD_VALID = 'Reset password hash is valid.';
44+
public const RESOURCE_ALREADY_REGISTERED = 'Resource "%s" is already registered.';
4245
public const RESOURCE_NOT_ALLOWED = 'You are not allowed to access this resource.';
46+
public const RESOURCE_NOT_FOUND = '%s not found.';
4347
public const RESTRICTION_DEPRECATION = 'Cannot use both "%s" and "%s" attributes on the same object.';
4448
public const RESTRICTION_IMAGE = 'File must be an image> Accepted mim type(s): %s';
4549
public const RESTRICTION_ROLES = 'At least one role is required.';
4650
public const ROLE_NOT_FOUND = 'Role not found.';
4751
public const SERVICE_NOT_FOUND = 'Service %s not found in the container.';
4852
public const SETTING_NOT_FOUND = 'Setting "%s" not found.';
53+
public const TEMPLATE_NOT_FOUND = 'Template "%s" not found.';
54+
public const UNSUPPORTED_MEDIA_TYPE = 'Unsupported Media Type.';
4955
public const USER_ACTIVATED = 'User account has been activated.';
5056
public const USER_ALREADY_ACTIVATED = 'User account is already active.';
5157
public const USER_ALREADY_DEACTIVATED = 'User account is already inactive.';
@@ -93,6 +99,25 @@ public static function mailSentUserActivation(string $email): string
9399
return sprintf(self::MAIL_SENT_USER_ACTIVATION, $email);
94100
}
95101

102+
public static function notAcceptable(array $types = []): string
103+
{
104+
if (count($types) === 0) {
105+
return self::NOT_ACCEPTABLE;
106+
}
107+
108+
return sprintf('%s Supported types: %s', self::NOT_ACCEPTABLE, implode(', ', $types));
109+
}
110+
111+
public static function resourceAlreadyRegistered(string $resource): string
112+
{
113+
return sprintf(self::RESOURCE_ALREADY_REGISTERED, $resource);
114+
}
115+
116+
public static function resourceNotFound(string $resource = 'Resource'): string
117+
{
118+
return sprintf(self::RESOURCE_NOT_FOUND, $resource);
119+
}
120+
96121
public static function restrictionDeprecation(string $first, string $second): string
97122
{
98123
return sprintf(self::RESTRICTION_DEPRECATION, $first, $second);
@@ -113,6 +138,20 @@ public static function settingNotFound(string $identifier): string
113138
return sprintf(self::SETTING_NOT_FOUND, $identifier);
114139
}
115140

141+
public static function templateNotFound(string $template): string
142+
{
143+
return sprintf(self::TEMPLATE_NOT_FOUND, $template);
144+
}
145+
146+
public static function unsupportedMediaType(array $types = []): string
147+
{
148+
if (count($types) === 0) {
149+
return self::UNSUPPORTED_MEDIA_TYPE;
150+
}
151+
152+
return sprintf('%s Supported types: %s', self::UNSUPPORTED_MEDIA_TYPE, implode(', ', $types));
153+
}
154+
116155
public static function validatorLengthMax(int $max): string
117156
{
118157
return sprintf(self::VALIDATOR_LENGTH_MAX, $max);

src/Core/src/App/src/Service/MailService.php

Lines changed: 13 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,18 @@
99
use Dot\DependencyInjection\Attribute\Inject;
1010
use Dot\Log\LoggerInterface;
1111
use Dot\Mail\Exception\MailException;
12-
use Mezzio\Template\TemplateRendererInterface;
1312
use Symfony\Component\Mailer\Exception\TransportExceptionInterface;
1413

1514
use function sprintf;
1615

1716
class MailService
1817
{
1918
#[Inject(
20-
TemplateRendererInterface::class,
2119
'dot-mail.service.default',
2220
'dot-log.default_logger',
2321
'config',
2422
)]
2523
public function __construct(
26-
private readonly TemplateRendererInterface $templateRenderer,
2724
protected \Dot\Mail\Service\MailService $mailService,
2825
protected LoggerInterface $logger,
2926
private readonly array $config,
@@ -33,20 +30,15 @@ public function __construct(
3330
/**
3431
* @throws MailException
3532
*/
36-
public function sendActivationMail(User $user): bool
33+
public function sendActivationMail(User $user, string $body): bool
3734
{
3835
if ($user->isActive()) {
3936
return false;
4037
}
4138

4239
$this->mailService->getMessage()->addTo($user->getDetail()->getEmail(), $user->getName());
4340
$this->mailService->setSubject('Welcome to ' . $this->config['application']['name']);
44-
$this->mailService->setBody(
45-
$this->templateRenderer->render('user::activate', [
46-
'config' => $this->config,
47-
'user' => $user,
48-
])
49-
);
41+
$this->mailService->setBody($body);
5042

5143
try {
5244
return $this->mailService->send()->isValid();
@@ -59,18 +51,13 @@ public function sendActivationMail(User $user): bool
5951
/**
6052
* @throws MailException
6153
*/
62-
public function sendResetPasswordRequestedMail(User $user): bool
54+
public function sendResetPasswordRequestedMail(User $user, string $body): bool
6355
{
6456
$this->mailService->getMessage()->addTo($user->getDetail()->getEmail(), $user->getName());
6557
$this->mailService->setSubject(
6658
'Reset password instructions for your ' . $this->config['application']['name'] . ' account'
6759
);
68-
$this->mailService->setBody(
69-
$this->templateRenderer->render('user::reset-password-requested', [
70-
'config' => $this->config,
71-
'user' => $user,
72-
])
73-
);
60+
$this->mailService->setBody($body);
7461

7562
try {
7663
return $this->mailService->send()->isValid();
@@ -83,18 +70,13 @@ public function sendResetPasswordRequestedMail(User $user): bool
8370
/**
8471
* @throws MailException
8572
*/
86-
public function sendResetPasswordCompletedMail(User $user): bool
73+
public function sendResetPasswordCompletedMail(User $user, string $body): bool
8774
{
8875
$this->mailService->getMessage()->addTo($user->getDetail()->getEmail(), $user->getName());
8976
$this->mailService->setSubject(
9077
'You have successfully reset the password for your ' . $this->config['application']['name'] . ' account'
9178
);
92-
$this->mailService->setBody(
93-
$this->templateRenderer->render('user::reset-password-completed', [
94-
'config' => $this->config,
95-
'user' => $user,
96-
])
97-
);
79+
$this->mailService->setBody($body);
9880

9981
try {
10082
return $this->mailService->send()->isValid();
@@ -107,16 +89,13 @@ public function sendResetPasswordCompletedMail(User $user): bool
10789
/**
10890
* @throws MailException
10991
*/
110-
public function sendWelcomeMail(User $user): bool
92+
public function sendRecoverIdentityMail(User $user, string $body): bool
11193
{
11294
$this->mailService->getMessage()->addTo($user->getDetail()->getEmail(), $user->getName());
113-
$this->mailService->setSubject('Welcome to ' . $this->config['application']['name']);
114-
$this->mailService->setBody(
115-
$this->templateRenderer->render('user::welcome', [
116-
'config' => $this->config,
117-
'user' => $user,
118-
])
95+
$this->mailService->setSubject(
96+
'Recover identity for your ' . $this->config['application']['name'] . ' account'
11997
);
98+
$this->mailService->setBody($body);
12099

121100
try {
122101
return $this->mailService->send()->isValid();
@@ -129,18 +108,11 @@ public function sendWelcomeMail(User $user): bool
129108
/**
130109
* @throws MailException
131110
*/
132-
public function sendRecoverIdentityMail(User $user): bool
111+
public function sendWelcomeMail(User $user, string $body): bool
133112
{
134113
$this->mailService->getMessage()->addTo($user->getDetail()->getEmail(), $user->getName());
135-
$this->mailService->setSubject(
136-
'Recover identity for your ' . $this->config['application']['name'] . ' account'
137-
);
138-
$this->mailService->setBody(
139-
$this->templateRenderer->render('user::recover-identity-requested', [
140-
'config' => $this->config,
141-
'user' => $user,
142-
])
143-
);
114+
$this->mailService->setSubject('Welcome to ' . $this->config['application']['name']);
115+
$this->mailService->setBody($body);
144116

145117
try {
146118
return $this->mailService->send()->isValid();

src/Core/src/Setting/src/ConfigProvider.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ public function __invoke(): array
1919
];
2020
}
2121

22-
public function getDependencies(): array
22+
private function getDependencies(): array
2323
{
2424
return [
2525
'factories' => [
@@ -28,7 +28,7 @@ public function getDependencies(): array
2828
];
2929
}
3030

31-
public function getDoctrineConfig(): array
31+
private function getDoctrineConfig(): array
3232
{
3333
return [
3434
'driver' => [

src/Core/src/User/src/Entity/User.php

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
use function array_map;
1919
use function bin2hex;
2020
use function md5;
21+
use function trim;
2122
use function uniqid;
2223

2324
#[ORM\Entity(repositoryClass: UserRepository::class)]
@@ -116,17 +117,6 @@ public function addResetPassword(UserResetPassword $resetPassword): void
116117
$this->resetPasswords->add($resetPassword);
117118
}
118119

119-
public function createResetPassword(): self
120-
{
121-
$this->resetPasswords->add(
122-
(new UserResetPassword())
123-
->setHash(self::generateHash())
124-
->setUser($this)
125-
);
126-
127-
return $this;
128-
}
129-
130120
public function getResetPasswords(): Collection
131121
{
132122
return $this->resetPasswords;
@@ -261,7 +251,7 @@ public static function generateHash(): string
261251

262252
public function getName(): string
263253
{
264-
return $this->getDetail()->getFirstName() . ' ' . $this->getDetail()->getLastName();
254+
return trim($this->getDetail()->getFirstName() . ' ' . $this->getDetail()->getLastName());
265255
}
266256

267257
public function isActive(): bool

src/User/src/Handler/PostUserCreateHandler.php

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ class PostUserCreateHandler implements RequestHandlerInterface
3535
CreateUserForm::class,
3636
MailService::class,
3737
'dot-log.default_logger',
38+
'config',
3839
)]
3940
public function __construct(
4041
protected UserServiceInterface $userService,
@@ -44,6 +45,7 @@ public function __construct(
4445
protected CreateUserForm $createUserForm,
4546
protected MailService $mailService,
4647
protected Logger $logger,
48+
protected array $config,
4749
) {
4850
}
4951

@@ -58,7 +60,11 @@ public function handle(ServerRequestInterface $request): ResponseInterface
5860
$user = $this->userService->saveUser((array) $this->createUserForm->getData());
5961
$this->messenger->addSuccess(Message::USER_CREATED);
6062
if ($user->getDetail()->hasEmail()) {
61-
$this->mailService->sendWelcomeMail($user);
63+
$body = $this->template->render('user::welcome', [
64+
'config' => $this->config,
65+
'user' => $user,
66+
]);
67+
$this->mailService->sendWelcomeMail($user, $body);
6268
}
6369

6470
return new EmptyResponse(StatusCodeInterface::STATUS_CREATED);

test/Unit/App/Entity/AbstractEntityTest.php

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
use AdminTest\Unit\UnitTest;
88
use Core\App\Entity\AbstractEntity;
99
use Core\App\Entity\EntityInterface;
10+
use DateTimeImmutable;
1011
use Ramsey\Uuid\UuidInterface;
1112

1213
class AbstractEntityTest extends UnitTest
@@ -18,6 +19,26 @@ public function getArrayCopy(): array
1819
{
1920
return [];
2021
}
22+
23+
public function getCreated(): ?DateTimeImmutable
24+
{
25+
return null;
26+
}
27+
28+
public function getCreatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): string
29+
{
30+
return '';
31+
}
32+
33+
public function getUpdated(): ?DateTimeImmutable
34+
{
35+
return null;
36+
}
37+
38+
public function getUpdatedFormatted(string $dateFormat = 'Y-m-d H:i:s'): ?string
39+
{
40+
return null;
41+
}
2142
};
2243

2344
$this->assertContainsOnlyInstancesOf(EntityInterface::class, [$entity]);

0 commit comments

Comments
 (0)