1+ <?php
2+
3+ namespace App \Synchronizer ;
4+
5+ use App \Synchronizer \Mapper \Mapper ;
6+ use App \Http \MailChimpClient ;
7+ use App \Synchronizer \Filter ;
8+
9+ class WebsiteToMailchimpSynchronizer
10+ {
11+ /**
12+ * @var Config
13+ */
14+ private $ config ;
15+
16+ /**
17+ * @var string
18+ */
19+ private $ configName ;
20+
21+ /**
22+ * @var MailChimpClient
23+ */
24+ private $ mailchimpClient ;
25+
26+ /**
27+ * @var Filter
28+ */
29+ private $ filter ;
30+
31+ /**
32+ * @var Mapper
33+ */
34+ private $ mapper ;
35+
36+ /**
37+ * Synchronizer constructor.
38+ *
39+ * @param string $configFileName file name of the config file
40+ *
41+ * @throws \App\Exceptions\ConfigException
42+ * @throws \Exception
43+ */
44+ public function __construct (string $ configFileName )
45+ {
46+ $ this ->config = new Config ($ configFileName );
47+ $ this ->configName = $ configFileName ;
48+
49+ $ mcCred = $ this ->config ->getMailchimpCredentials ();
50+ $ this ->mailchimpClient = new MailChimpClient ($ mcCred ['apikey ' ], $ this ->config ->getMailchimpListId ());
51+
52+ $ this ->filter = new Filter ($ this ->config ->getFieldMaps (), $ this ->config ->getSyncAll ());
53+ $ this ->mapper = new Mapper ($ this ->config ->getFieldMaps ());
54+ }
55+
56+ /**
57+ * Synchronize a single contact from website data to Mailchimp
58+ *
59+ * @param array $websiteData Data from website in internal format (keys match crmKey from config)
60+ *
61+ * @return array The Mailchimp API response
62+ *
63+ * @throws \App\Exceptions\InvalidEmailException
64+ * @throws \App\Exceptions\EmailComplianceException
65+ * @throws \App\Exceptions\MailchimpClientException
66+ * @throws \App\Exceptions\AlreadyInListException
67+ * @throws \App\Exceptions\FakeEmailException
68+ * @throws \App\Exceptions\UnsubscribedEmailException
69+ * @throws \App\Exceptions\MergeFieldException
70+ * @throws \App\Exceptions\MailchimpTooManySubscriptionsException
71+ * @throws \App\Exceptions\ArchivedException
72+ */
73+ public function syncSingle (array $ websiteData )
74+ {
75+ // Validate that we have an email address
76+ $ emailField = $ this ->getEmailFieldFromConfig ();
77+ if (empty ($ websiteData [$ emailField ])) {
78+ throw new \App \Exceptions \InvalidEmailException ('Email address is required ' );
79+ }
80+
81+ // Normalize the email address
82+ $ websiteData [$ emailField ] = strtolower (trim ($ websiteData [$ emailField ]));
83+
84+ // Fill missing CRM keys with empty values
85+ $ websiteData = $ this ->fillMissingCrmKeys ($ websiteData );
86+
87+ // Validate email format
88+ if (!filter_var ($ websiteData [$ emailField ], FILTER_VALIDATE_EMAIL )) {
89+ throw new \App \Exceptions \InvalidEmailException ('Invalid email format: ' . $ websiteData [$ emailField ]);
90+ }
91+
92+ // Map the website data to Mailchimp format
93+ $ mailchimpData = $ this ->mapper ->crmToMailchimp ($ websiteData );
94+
95+ // Ensure we have the email address in the correct format for Mailchimp
96+ $ mailchimpData ['email_address ' ] = $ websiteData [$ emailField ];
97+
98+ // Set the status to subscribed for new subscribers
99+ $ mailchimpData ['status ' ] = 'subscribed ' ;
100+
101+ // Add the subscriber to Mailchimp
102+ $ response = $ this ->mailchimpClient ->putSubscriber ($ mailchimpData );
103+
104+ // Add tags to new subscriber
105+ $ tags = [$ this ->config ->getNewTag ()];
106+ if (isset ($ websiteData ['notesCountry ' ])) {
107+ $ tags [] = $ websiteData ['notesCountry ' ];
108+ }
109+ $ this ->mailchimpClient ->addTagsToSubscriber ($ response ['id ' ], $ tags );
110+
111+ return $ response ;
112+ }
113+
114+ /**
115+ * Ensures all required CRM keys are present in the data array, filling missing ones with empty values.
116+ *
117+ * @param array $data
118+ * @return array
119+ */
120+ private function fillMissingCrmKeys (array $ data ): array
121+ {
122+ foreach ($ this ->config ->getFieldMaps () as $ fieldMap ) {
123+ $ crmKey = $ fieldMap ->getCrmKey ();
124+ if (!array_key_exists ($ crmKey , $ data )) {
125+ $ data [$ crmKey ] = null ;
126+ }
127+ }
128+ return $ data ;
129+ }
130+
131+ /**
132+ * Get the email field name from the config
133+ *
134+ * @return string The email field name
135+ * @throws \App\Exceptions\ConfigException
136+ */
137+ private function getEmailFieldFromConfig (): string
138+ {
139+ $ fieldMaps = $ this ->config ->getFieldMaps ();
140+
141+ foreach ($ fieldMaps as $ fieldMap ) {
142+ if ($ fieldMap ->isEmail ()) {
143+ return $ fieldMap ->getCrmKey ();
144+ }
145+ }
146+
147+ throw new \App \Exceptions \ConfigException ('No email field defined in configuration ' );
148+ }
149+ }
0 commit comments