Skip to content

Instantly share code, notes, and snippets.

@romaricdrigon
Last active September 17, 2019 06:51
Show Gist options
  • Save romaricdrigon/4a7c9d5af79f6cee4ac15566505c36c2 to your computer and use it in GitHub Desktop.
Save romaricdrigon/4a7c9d5af79f6cee4ac15566505c36c2 to your computer and use it in GitHub Desktop.
FileTransport to store sent emails on disk
<?php
namespace App\Email;
use Symfony\Bridge\Twig\Mime\TemplatedEmail;
use Symfony\Component\Finder\Finder;
use Symfony\Component\Mime\Email;
/**
* Helper to deal with messages as dumped by FileTransport.
* Everything is public and static, as it will be used in unit/functional tests.
*/
class EmailFileHelper
{
public static $path = __DIR__.'/../../../'.FileTransport::FOLDER;
private static $finder; // Singleton to save a little bit of memory
public static function countMessages()
{
return self::getFinder()->count();
}
public static function has(int $emailIndex): bool
{
$files = iterator_to_array(self::getFinder()->getIterator(), false);
return isset($files[$emailIndex]);
}
public static function read(int $emailIndex): Email
{
$files = iterator_to_array(self::getFinder()->getIterator(), false);
if (!isset($files[$emailIndex])) {
throw new \Exception('No emails available for index '.$emailIndex);
}
$file = $files[$emailIndex];
$data = $file->getContents();
$unserialized = unserialize($data);
if (TemplatedEmail::class === $unserialized['class']) {
// TemplatedEmail serialization format is incompatible
$email = new TemplatedEmail();
$email->unserialize($unserialized['data']);
} else {
// We consider it is a normal Email
$email = new Email();
$email->unserialize($unserialized['data']);
}
return $email;
}
public function getFilename(int $emailIndex): string
{
$files = iterator_to_array(self::getFinder()->getIterator(), false);
if (!isset($files[$emailIndex])) {
throw new \Exception('No emails available for index '.$emailIndex);
}
return $files[$emailIndex]->getPathname();
}
private static function getFinder(): Finder
{
if (!self::$finder) {
self::$finder = (new Finder())
->in(self::$path)
->name('*.ser')
->files()
;
}
return self::$finder;
}
}
<?php
namespace App\Email;
use Symfony\Component\Filesystem\Filesystem;
use Symfony\Component\Mailer\SentMessage;
use Symfony\Component\Mailer\Transport\AbstractTransport;
use Symfony\Component\Mime\Email;
/**
* File transport used in tests, we store messages on disk.
*/
class FileTransport extends AbstractTransport
{
const FOLDER = 'var/emails';
const FILE_EXTENSION = 'ser';
private $path;
public function setProjectDir(string $path): void
{
$this->path = sprintf('%s/%s', $path, self::FOLDER);
}
protected function doSend(SentMessage $message): void
{
$filesystem = new Filesystem();
if (!$filesystem->exists($this->path)) {
$filesystem->mkdir($this->path);
}
$filename = uniqid('message_');
// We should get rendered Message - called "original", the other "RawMessage" is a Generator to generate body chunk-by-chunk.
$email = $message->getOriginalMessage();
// We can serialize only Emails
if (!$email instanceof Email) {
return;
}
// We keep classname around, as TemplatedEmail and Email serialization are incompatible
$serialized = [
'class' => get_class($email),
'data' => $email->serialize(),
];
$filesystem->dumpFile(
sprintf('%s/%s.%s', $this->path, $filename, self::FILE_EXTENSION),
serialize($serialized)
);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment