dev-think-one /
laravel-notification-tracker
| 1 | <?php |
||
| 2 | |||
| 3 | namespace NotificationTracker\Mail; |
||
| 4 | |||
| 5 | use Illuminate\Support\Str; |
||
| 6 | use NotificationTracker\Models\TrackedChannel; |
||
| 7 | use Symfony\Component\Mime\Email; |
||
| 8 | use Symfony\Component\Mime\Part\Multipart\AlternativePart; |
||
| 9 | use Symfony\Component\Mime\Part\Multipart\MixedPart; |
||
| 10 | use Symfony\Component\Mime\Part\Multipart\RelatedPart; |
||
| 11 | use Symfony\Component\Mime\Part\TextPart; |
||
| 12 | |||
| 13 | class MailConverter |
||
| 14 | { |
||
| 15 | protected bool $pixelAdded = false; |
||
| 16 | |||
| 17 | 3 | public function __construct( |
|
| 18 | protected TrackedChannel $tracker, |
||
| 19 | protected Email $email, |
||
| 20 | ) { |
||
| 21 | 3 | } |
|
| 22 | |||
| 23 | 3 | public function format() |
|
| 24 | { |
||
| 25 | 3 | $emailBody = $this->email->getBody(); |
|
| 26 | if ( |
||
| 27 | 3 | ($emailBody instanceof (AlternativePart::class)) || |
|
|
0 ignored issues
–
show
Bug
introduced
by
Loading history...
|
|||
| 28 | ($emailBody instanceof (MixedPart::class)) || |
||
| 29 | 3 | ($emailBody instanceof (RelatedPart::class)) |
|
| 30 | ) { |
||
| 31 | 3 | $newParts = []; |
|
| 32 | 3 | foreach ($emailBody->getParts() as $part) { |
|
| 33 | 3 | if ($part->getMediaSubtype() === 'html') { |
|
| 34 | 3 | $newParts[] = new TextPart( |
|
| 35 | 3 | $this->makeTrackable($part->getBody()), |
|
| 36 | 3 | $this->email->getHtmlCharset(), |
|
| 37 | 3 | $part->getMediaSubtype(), |
|
| 38 | 3 | null |
|
| 39 | 3 | ); |
|
| 40 | |||
| 41 | 3 | continue; |
|
| 42 | } |
||
| 43 | |||
| 44 | 3 | if ($part->getMediaSubtype() === 'alternative') { |
|
| 45 | if (method_exists($part, 'getParts')) { |
||
| 46 | foreach ($part->getParts() as $subPart) { |
||
| 47 | if ($subPart->getMediaSubtype() == 'html') { |
||
| 48 | $newParts[] = new TextPart( |
||
| 49 | $this->makeTrackable($subPart->getBody()), |
||
| 50 | $this->email->getHtmlCharset(), |
||
| 51 | $subPart->getMediaSubtype(), |
||
| 52 | null |
||
| 53 | ); |
||
| 54 | |||
| 55 | break; |
||
| 56 | } |
||
| 57 | } |
||
| 58 | } |
||
| 59 | |||
| 60 | continue; |
||
| 61 | } |
||
| 62 | |||
| 63 | 3 | $newParts[] = $part; |
|
| 64 | } |
||
| 65 | 3 | $this->email->setBody(new (get_class($emailBody))(...$newParts)); |
|
| 66 | |||
| 67 | 3 | return; |
|
| 68 | } |
||
| 69 | |||
| 70 | if ($emailBody->getMediaSubtype() == 'html') { |
||
| 71 | $this->email->setBody( |
||
| 72 | new TextPart( |
||
| 73 | $this->makeTrackable($emailBody->getBody()), |
||
| 74 | $this->email->getHtmlCharset(), |
||
| 75 | $emailBody->getMediaSubtype(), |
||
| 76 | null |
||
| 77 | ) |
||
| 78 | ); |
||
| 79 | |||
| 80 | return; |
||
| 81 | } |
||
| 82 | } |
||
| 83 | |||
| 84 | 3 | protected function makeTrackable(string $content): string |
|
| 85 | { |
||
| 86 | 3 | $content = $this->addPixelImage($content); |
|
| 87 | |||
| 88 | // TODO: future extension: add other trackers like click? |
||
| 89 | |||
| 90 | 3 | return $content; |
|
| 91 | } |
||
| 92 | |||
| 93 | 3 | protected function addPixelImage(string $content): string |
|
| 94 | { |
||
| 95 | 3 | if ($this->pixelAdded) { |
|
| 96 | return $content; |
||
| 97 | } |
||
| 98 | |||
| 99 | do { |
||
| 100 | 3 | $br = Str::random(); |
|
| 101 | 3 | } while (str_contains($content, $br)); |
|
| 102 | 3 | $content = str_replace("\n", $br, $content); |
|
| 103 | |||
| 104 | 3 | if (preg_match('/^(.*<body[^>]*>)(.*)$/im', $content, $matches)) { |
|
| 105 | 3 | $content = $matches[1] . $this->tracker->getPixelImageHtml() . $matches[2]; |
|
| 106 | } else { |
||
| 107 | $content .= $this->tracker->getPixelImageHtml(); |
||
| 108 | } |
||
| 109 | |||
| 110 | 3 | $content = str_replace($br, "\n", $content); |
|
| 111 | |||
| 112 | 3 | $this->pixelAdded = true; |
|
| 113 | |||
| 114 | 3 | return $content; |
|
| 115 | } |
||
| 116 | } |
||
| 117 |