Total Complexity | 83 |
Total Lines | 491 |
Duplicated Lines | 0 % |
Changes | 12 | ||
Bugs | 2 | Features | 2 |
Complex classes like SparkPostHelper often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use SparkPostHelper, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
22 | class SparkPostHelper |
||
23 | { |
||
24 | use Configurable; |
||
25 | |||
26 | const FROM_SITECONFIG = "SiteConfig"; |
||
27 | const FROM_ADMIN = "Admin"; |
||
28 | const FROM_DEFAULT = "Default"; |
||
29 | |||
30 | /** |
||
31 | * Client instance |
||
32 | * |
||
33 | * @var ?\LeKoala\SparkPost\Api\SparkPostApiClient |
||
34 | */ |
||
35 | protected static $client; |
||
36 | |||
37 | /** |
||
38 | * Get the mailer instance |
||
39 | * |
||
40 | * @return MailerInterface |
||
41 | */ |
||
42 | public static function getMailer() |
||
45 | } |
||
46 | |||
47 | /** |
||
48 | * @param MailerInterface $mailer |
||
49 | * @return \Symfony\Component\Mailer\Transport\AbstractTransport|SparkPostApiTransport |
||
50 | */ |
||
51 | public static function getTransportFromMailer($mailer) |
||
52 | { |
||
53 | $r = new ReflectionObject($mailer); |
||
54 | $p = $r->getProperty('transport'); |
||
55 | $p->setAccessible(true); |
||
56 | return $p->getValue($mailer); |
||
57 | } |
||
58 | |||
59 | /** |
||
60 | * @return string |
||
61 | */ |
||
62 | public static function getApiKey() |
||
63 | { |
||
64 | return self::config()->api_key; |
||
65 | } |
||
66 | |||
67 | /** |
||
68 | * Get the api client instance |
||
69 | * @return SparkPostApiClient |
||
70 | * @throws Exception |
||
71 | */ |
||
72 | public static function getClient() |
||
73 | { |
||
74 | if (!self::$client) { |
||
75 | $key = self::getApiKey(); |
||
76 | if (empty($key)) { |
||
77 | throw new \Exception("api_key is not configured for " . __class__); |
||
78 | } |
||
79 | self::$client = new SparkPostApiClient($key); |
||
80 | if (Director::isDev()) { |
||
81 | //@phpstan-ignore-next-line |
||
82 | self::$client->setCurlOption(CURLOPT_VERBOSE, true); |
||
83 | } |
||
84 | if (Environment::getEnv("SPARKPOST_EU")) { |
||
85 | self::$client->setEuEndpoint(true); |
||
86 | } |
||
87 | $subaccountId = self::config()->subaccount_id; |
||
88 | if ($subaccountId) { |
||
89 | self::$client->setSubaccount($subaccountId); |
||
90 | } |
||
91 | } |
||
92 | return self::$client; |
||
93 | } |
||
94 | |||
95 | /** |
||
96 | * Get the api client instance |
||
97 | * @return \LeKoala\SparkPost\Api\SparkPostApiClient |
||
98 | * @throws Exception |
||
99 | */ |
||
100 | public static function getMasterClient() |
||
101 | { |
||
102 | $masterKey = self::config()->master_api_key; |
||
103 | if (!$masterKey) { |
||
104 | return self::getClient(); |
||
105 | } |
||
106 | $client = new SparkPostApiClient($masterKey); |
||
107 | return $client; |
||
108 | } |
||
109 | |||
110 | /** |
||
111 | * Get the log folder and create it if necessary |
||
112 | * |
||
113 | * @return string |
||
114 | */ |
||
115 | public static function getLogFolder() |
||
116 | { |
||
117 | $logFolder = BASE_PATH . '/' . self::config()->log_folder; |
||
118 | if (!is_dir($logFolder)) { |
||
119 | mkdir($logFolder, 0755, true); |
||
120 | } |
||
121 | return $logFolder; |
||
122 | } |
||
123 | |||
124 | |||
125 | /** |
||
126 | * Process environment variable to configure this module |
||
127 | * |
||
128 | * @return void |
||
129 | */ |
||
130 | public static function init() |
||
131 | { |
||
132 | // Regular api key used for sending emails (including subaccount support) |
||
133 | $api_key = self::getEnvApiKey(); |
||
134 | if ($api_key) { |
||
135 | self::config()->api_key = $api_key; |
||
136 | } |
||
137 | |||
138 | // Master api key that is used to configure the account. If no api key is defined, the master api key is used |
||
139 | $master_api_key = self::getEnvMasterApiKey(); |
||
140 | if ($master_api_key) { |
||
141 | self::config()->master_api_key = $master_api_key; |
||
142 | if (!self::config()->api_key) { |
||
143 | self::config()->api_key = $master_api_key; |
||
144 | } |
||
145 | } |
||
146 | |||
147 | $sending_disabled = self::getEnvSendingDisabled(); |
||
148 | if ($sending_disabled === false) { |
||
149 | // In dev, if we didn't set a value, disable by default |
||
150 | // This can avoid sending emails by mistake :-) oops! |
||
151 | if (Director::isDev() && !self::hasEnvSendingDisabled()) { |
||
152 | $sending_disabled = true; |
||
153 | } |
||
154 | } |
||
155 | if ($sending_disabled) { |
||
156 | self::config()->disable_sending = $sending_disabled; |
||
157 | } |
||
158 | $enable_logging = self::getEnvEnableLogging(); |
||
159 | if ($enable_logging) { |
||
160 | self::config()->enable_logging = $enable_logging; |
||
161 | } |
||
162 | $subaccount_id = self::getEnvSubaccountId(); |
||
163 | if ($subaccount_id) { |
||
164 | self::config()->subaccount_id = $subaccount_id; |
||
165 | } |
||
166 | |||
167 | // We have a key, we can register the transport |
||
168 | if (self::config()->api_key) { |
||
169 | self::registerTransport(); |
||
170 | } |
||
171 | } |
||
172 | |||
173 | /** |
||
174 | * @return mixed |
||
175 | */ |
||
176 | public static function getEnvApiKey() |
||
179 | } |
||
180 | |||
181 | /** |
||
182 | * @return mixed |
||
183 | */ |
||
184 | public static function getEnvMasterApiKey() |
||
185 | { |
||
186 | return Environment::getEnv('SPARKPOST_MASTER_API_KEY'); |
||
187 | } |
||
188 | |||
189 | /** |
||
190 | * @return mixed |
||
191 | */ |
||
192 | public static function getEnvSendingDisabled() |
||
193 | { |
||
194 | return Environment::getEnv('SPARKPOST_SENDING_DISABLED'); |
||
195 | } |
||
196 | |||
197 | /** |
||
198 | * @return bool |
||
199 | */ |
||
200 | public static function hasEnvSendingDisabled() |
||
201 | { |
||
202 | return Environment::hasEnv('SPARKPOST_SENDING_DISABLED'); |
||
203 | } |
||
204 | |||
205 | /** |
||
206 | * @return mixed |
||
207 | */ |
||
208 | public static function getEnvEnableLogging() |
||
209 | { |
||
210 | return Environment::getEnv('SPARKPOST_ENABLE_LOGGING'); |
||
211 | } |
||
212 | |||
213 | /** |
||
214 | * @return mixed |
||
215 | */ |
||
216 | public static function getEnvSubaccountId() |
||
217 | { |
||
218 | return Environment::getEnv('SPARKPOST_SUBACCOUNT_ID'); |
||
219 | } |
||
220 | |||
221 | /** |
||
222 | * @return mixed |
||
223 | */ |
||
224 | public static function getSubaccountId() |
||
225 | { |
||
226 | return self::config()->subaccount_id; |
||
227 | } |
||
228 | |||
229 | /** |
||
230 | * @return mixed |
||
231 | */ |
||
232 | public static function getEnvForceSender() |
||
233 | { |
||
234 | return Environment::getEnv('SPARKPOST_FORCE_SENDER'); |
||
235 | } |
||
236 | |||
237 | /** |
||
238 | * @return mixed |
||
239 | */ |
||
240 | public static function getWebhookUsername() |
||
241 | { |
||
242 | return self::config()->webhook_username; |
||
243 | } |
||
244 | |||
245 | /** |
||
246 | * @return mixed |
||
247 | */ |
||
248 | public static function getWebhookPassword() |
||
249 | { |
||
250 | return self::config()->webhook_password; |
||
251 | } |
||
252 | |||
253 | /** |
||
254 | * Register the transport with the client |
||
255 | * |
||
256 | * @return Mailer The updated mailer |
||
257 | * @throws Exception |
||
258 | */ |
||
259 | public static function registerTransport() |
||
260 | { |
||
261 | $client = self::getClient(); |
||
262 | $transport = new SparkPostApiTransport($client); |
||
263 | $mailer = new Mailer($transport); |
||
264 | Injector::inst()->registerService($mailer, MailerInterface::class); |
||
265 | return $mailer; |
||
266 | } |
||
267 | |||
268 | /** |
||
269 | * Update admin email so that we use our config email |
||
270 | * |
||
271 | * @return void |
||
272 | */ |
||
273 | public static function forceAdminEmailOverride() |
||
274 | { |
||
275 | Config::modify()->set(Email::class, 'admin_email', self::resolveDefaultFromEmailType()); |
||
276 | } |
||
277 | |||
278 | /** |
||
279 | * @param string $email |
||
280 | * @return bool |
||
281 | */ |
||
282 | public static function isEmailSuppressed($email) |
||
291 | } |
||
292 | |||
293 | /** |
||
294 | * @param string $email |
||
295 | * @return void |
||
296 | */ |
||
297 | public static function removeSuppression($email) |
||
298 | { |
||
299 | self::getClient()->deleteSuppression($email); |
||
300 | } |
||
301 | |||
302 | /** |
||
303 | * Check if email is ready to send emails |
||
304 | * |
||
305 | * @param string $email |
||
306 | * @return boolean |
||
307 | */ |
||
308 | public static function isEmailDomainReady($email) |
||
309 | { |
||
310 | if (!$email) { |
||
311 | return false; |
||
312 | } |
||
313 | $email = EmailUtils::get_email_from_rfc_email($email); |
||
314 | $parts = explode("@", $email); |
||
315 | if (count($parts) != 2) { |
||
316 | return false; |
||
317 | } |
||
318 | $client = SparkPostHelper::getClient(); |
||
319 | try { |
||
320 | $domain = $client->getSendingDomain(strtolower($parts[1])); |
||
321 | } catch (Exception $ex) { |
||
322 | return false; |
||
323 | } |
||
324 | if (!$domain) { |
||
|
|||
325 | return false; |
||
326 | } |
||
327 | if ($domain['status']['dkim_status'] != 'valid') { |
||
328 | return false; |
||
329 | } |
||
330 | if ($domain['status']['compliance_status'] != 'valid') { |
||
331 | return false; |
||
332 | } |
||
333 | if ($domain['status']['ownership_verified'] != true) { |
||
334 | return false; |
||
335 | } |
||
336 | return true; |
||
337 | } |
||
338 | |||
339 | /** |
||
340 | * Resolve default send from address |
||
341 | * |
||
342 | * Keep in mind that an email using send() without a from |
||
343 | * will inject the admin_email. Therefore, SiteConfig |
||
344 | * will not be used |
||
345 | * See forceAdminEmailOverride() or use override_admin_email config |
||
346 | * |
||
347 | * @param string $from |
||
348 | * @param bool $createDefault |
||
349 | * @return string|array<string,string>|false |
||
350 | */ |
||
351 | public static function resolveDefaultFromEmail($from = null, $createDefault = true) |
||
352 | { |
||
353 | $configEmail = self::getSenderFromSiteConfig(); |
||
354 | $original_from = $from; |
||
355 | if (!empty($from)) { |
||
356 | // We have a set email but sending from admin => override if flag is set |
||
357 | if (self::isAdminEmail($from) && $configEmail && self::config()->override_admin_email) { |
||
358 | return $configEmail; |
||
359 | } |
||
360 | // If we have a sender, validate its email |
||
361 | $from = EmailUtils::get_email_from_rfc_email($from); |
||
362 | if (filter_var($from, FILTER_VALIDATE_EMAIL)) { |
||
363 | return $original_from; |
||
364 | } |
||
365 | } |
||
366 | // Look in siteconfig for default sender |
||
367 | if ($configEmail) { |
||
368 | return $configEmail; |
||
369 | } |
||
370 | // Use admin email if set |
||
371 | if ($adminEmail = Email::config()->admin_email) { |
||
372 | if (is_array($adminEmail) && count($adminEmail) > 0) { |
||
373 | $email = array_keys($adminEmail)[0]; |
||
374 | return [$email => $adminEmail[$email]]; |
||
375 | } elseif (is_string($adminEmail)) { |
||
376 | return $adminEmail; |
||
377 | } |
||
378 | } |
||
379 | // If we still don't have anything, create something based on the domain |
||
380 | if ($createDefault) { |
||
381 | return self::createDefaultEmail(); |
||
382 | } |
||
383 | return false; |
||
384 | } |
||
385 | |||
386 | /** |
||
387 | * Returns what type of default email is used |
||
388 | * |
||
389 | * @return string |
||
390 | */ |
||
391 | public static function resolveDefaultFromEmailType() |
||
392 | { |
||
393 | // Look in siteconfig for default sender |
||
394 | if (self::getSenderFromSiteConfig()) { |
||
395 | return self::FROM_SITECONFIG; |
||
396 | } |
||
397 | // Is admin email set ? |
||
398 | if (Email::config()->admin_email) { |
||
399 | return self::FROM_ADMIN; |
||
400 | } |
||
401 | return self::FROM_DEFAULT; |
||
402 | } |
||
403 | |||
404 | /** |
||
405 | * @return string|false |
||
406 | */ |
||
407 | public static function getSenderFromSiteConfig() |
||
408 | { |
||
409 | $config = SiteConfig::current_site_config(); |
||
410 | $config_field = self::config()->siteconfig_from; |
||
411 | if ($config_field && !empty($config->$config_field)) { |
||
412 | return $config->$config_field; |
||
413 | } |
||
414 | return false; |
||
415 | } |
||
416 | |||
417 | /** |
||
418 | * @param string $email |
||
419 | * @return boolean |
||
420 | */ |
||
421 | public static function isAdminEmail($email) |
||
430 | } |
||
431 | |||
432 | /** |
||
433 | * @param string $email |
||
434 | * @return boolean |
||
435 | */ |
||
436 | public static function isDefaultEmail($email) |
||
437 | { |
||
438 | $rfc_email = EmailUtils::get_email_from_rfc_email($email); |
||
439 | return $rfc_email == self::createDefaultEmail(); |
||
440 | } |
||
441 | |||
442 | /** |
||
443 | * Resolve default send to address |
||
444 | * |
||
445 | * @param string|array<mixed>|null $to |
||
446 | * @return string|array<mixed>|null |
||
447 | */ |
||
448 | public static function resolveDefaultToEmail($to = null) |
||
449 | { |
||
450 | // In case of multiple recipients, do not validate anything |
||
451 | if (is_array($to) || strpos($to, ',') !== false) { |
||
452 | return $to; |
||
453 | } |
||
454 | $original_to = $to; |
||
455 | if (!empty($to)) { |
||
456 | $to = EmailUtils::get_email_from_rfc_email($to); |
||
457 | if (filter_var($to, FILTER_VALIDATE_EMAIL)) { |
||
458 | return $original_to; |
||
459 | } |
||
460 | } |
||
461 | $config = SiteConfig::current_site_config(); |
||
462 | $config_field = self::config()->siteconfig_to; |
||
463 | if ($config_field && !empty($config->$config_field)) { |
||
464 | return $config->$config_field; |
||
465 | } |
||
466 | if ($admin = Email::config()->admin_email) { |
||
467 | return $admin; |
||
468 | } |
||
469 | return null; |
||
470 | } |
||
471 | |||
472 | /** |
||
473 | * Create a sensible default address based on domain name |
||
474 | * |
||
475 | * @return string |
||
476 | */ |
||
477 | public static function createDefaultEmail() |
||
487 | } |
||
488 | |||
489 | /** |
||
490 | * Is logging enabled? |
||
491 | * |
||
492 | * @return bool |
||
493 | */ |
||
494 | public static function getLoggingEnabled() |
||
500 | } |
||
501 | |||
502 | /** |
||
503 | * Is sending enabled? |
||
504 | * |
||
505 | * @return bool |
||
506 | */ |
||
507 | public static function getSendingEnabled() |
||
513 | } |
||
514 | } |
||
515 |
This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.
Consider making the comparison explicit by using
empty(..)
or! empty(...)
instead.