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
![]() |
|||
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 |