PageRenderTime 51ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/backend/modules/mailmotor/engine/helper.php

http://github.com/forkcms/forkcms
PHP | 1106 lines | 488 code | 171 blank | 447 comment | 55 complexity | 754973c4453f358becd1e75108546976 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, MIT, AGPL-3.0, LGPL-2.1, BSD-3-Clause
  1. <?php
  2. /*
  3. * This file is part of Fork CMS.
  4. *
  5. * For the full copyright and license information, please view the license
  6. * file that was distributed with this source code.
  7. */
  8. /**
  9. * In this file we store all generic functions that we will be using to communicate with CampaignMonitor
  10. *
  11. * @author Dave Lens <dave.lens@netlash.com>
  12. */
  13. class BackendMailmotorCMHelper
  14. {
  15. /**
  16. * Checks if a valid CM account is set up
  17. *
  18. * @return bool
  19. */
  20. public static function checkAccount()
  21. {
  22. try
  23. {
  24. self::getCM();
  25. }
  26. catch(Exception $e)
  27. {
  28. return false;
  29. }
  30. // if we made it here, the account was valid
  31. return true;
  32. }
  33. /**
  34. * Creates a new client
  35. *
  36. * @param string $companyName The client company name.
  37. * @param string $contactName The personal name of the principle contact for this client.
  38. * @param string $email An email address to which this client will be sent application-related emails.
  39. * @param string[optional] $country This client’s country.
  40. * @param string[optional] $timezone Client timezone for tracking and reporting data.
  41. */
  42. public static function createClient($companyName, $contactName, $email, $country = 'Belgium', $timezone = '(GMT+01:00) Brussels, Copenhagen, Madrid, Paris')
  43. {
  44. // create client
  45. $clientId = self::getCM()->createClient($companyName, $contactName, $email, $country, $timezone);
  46. // add client ID as a module setting for mailmotor
  47. BackendModel::setModuleSetting('mailmotor', 'cm_client_id', $clientId);
  48. }
  49. /**
  50. * Creates a new custom field for a given group
  51. *
  52. * @param string $name The name of the custom field.
  53. * @param int $groupId The group ID you want to add the custom field for.
  54. * @return bool
  55. */
  56. public static function createCustomField($name, $groupId)
  57. {
  58. // get CM ID for this list
  59. $listId = self::getCampaignMonitorID('list', $groupId);
  60. // list ID found
  61. if(!empty($listId))
  62. {
  63. // create the field
  64. self::getCM()->createCustomField($name, 'text', null, $listId);
  65. // return true
  66. return true;
  67. }
  68. // if we made it here, return false
  69. return false;
  70. }
  71. /**
  72. * Deletes a custom field from a given group
  73. *
  74. * @param string $name The name of the custom field.
  75. * @param string $groupId The CampaignMonitor ID of the list you want to remove the custom field from.
  76. */
  77. public static function deleteCustomField($name, $groupId)
  78. {
  79. // get CM ID for this list
  80. $listId = self::getCampaignMonitorID('list', $groupId);
  81. // list ID found
  82. if(!empty($listId))
  83. {
  84. // create the field
  85. self::getCM()->deleteCustomField($name, $listId);
  86. // return true
  87. return true;
  88. }
  89. // if we made it here, return false
  90. return false;
  91. }
  92. /**
  93. * Deletes one or more groups
  94. *
  95. * @param mixed $ids The ids to delete.
  96. */
  97. public static function deleteGroups($ids)
  98. {
  99. $db = BackendModel::getDB(true);
  100. // if $ids is not an array, make one
  101. $ids = (!is_array($ids)) ? array($ids) : $ids;
  102. /*
  103. * I know this is messy, but since you can remove multiple groups at the same time in the datagrid ŕnd remove the record in CM
  104. * we need to loop the ID's one by one
  105. */
  106. // loop the list
  107. foreach($ids as $id)
  108. {
  109. // a list was deleted
  110. if(self::getCM()->deleteList(self::getCampaignMonitorID('list', $id)))
  111. {
  112. // delete group
  113. BackendMailmotorModel::deleteGroups($id);
  114. // delete CampaignMonitor reference
  115. $db->delete('mailmotor_campaignmonitor_ids', 'type = ? AND other_id = ?', array('list', $id));
  116. }
  117. }
  118. }
  119. /**
  120. * Deletes one or more mailings
  121. *
  122. * @param mixed $ids The ids to delete.
  123. */
  124. public static function deleteMailings($ids)
  125. {
  126. // if $ids is not an array, make one
  127. $ids = (!is_array($ids)) ? array($ids) : $ids;
  128. /*
  129. * I know this is messy, but since you can remove multiple mailings at the same time in the datagrid ŕnd remove the record in CM
  130. * we need to loop the ID's one by one
  131. */
  132. // loop the list
  133. foreach($ids as $id)
  134. {
  135. /*
  136. Depending on when you call this method it may or may not trigger an exception due
  137. to emails no longer existing with CM. That's why this bit is in a try/catch.
  138. */
  139. try
  140. {
  141. self::getCM()->deleteCampaign(self::getCampaignMonitorID('campaign', $id));
  142. }
  143. catch(Exception $e)
  144. {
  145. // ignore exception
  146. }
  147. // delete group
  148. BackendMailmotorModel::delete($id);
  149. }
  150. }
  151. /**
  152. * Returns all bounces
  153. *
  154. * @param int $id The id of the campaign.
  155. * @return array
  156. */
  157. public static function getBounces($id)
  158. {
  159. // get campaignmonitor ID
  160. $cmId = self::getCampaignMonitorID('campaign', $id);
  161. // get all bounces from CM
  162. $bounces = BackendMailmotorCMHelper::getCM()->getCampaignBounces($cmId);
  163. // get all addresses
  164. $addresses = BackendMailmotorModel::getAddressesAsPairs();
  165. // no bounces found
  166. if(empty($bounces)) return array();
  167. // loop the bounces, check what bounces are still in our database
  168. foreach($bounces as $key => $bounce)
  169. {
  170. // check if the bounced address is in the full list of addresses
  171. if(!in_array($bounce['email'], $addresses)) unset($bounces[$key]);
  172. }
  173. // return the bounces
  174. return (array) $bounces;
  175. }
  176. /**
  177. * Inserts a record into the mailmotor_campaignmonitor_ids table
  178. *
  179. * @param string $type The type to insert.
  180. * @param string $otherId The ID in our tables.
  181. * @return string
  182. */
  183. public static function getCampaignMonitorID($type, $otherId)
  184. {
  185. return BackendModel::getDB()->getVar(
  186. 'SELECT cm_id
  187. FROM mailmotor_campaignmonitor_ids
  188. WHERE type = ? AND other_id = ?',
  189. array($type, $otherId)
  190. );
  191. }
  192. /**
  193. * Returns the CM IDs for a given list of group IDs
  194. *
  195. * @param array $groupIds The IDs of the groups.
  196. * @return array
  197. */
  198. public static function getCampaignMonitorIDsForGroups(array $groupIds)
  199. {
  200. // stop here if no groups are found
  201. if(empty($groupIds)) return array();
  202. // fetch campaignmonitor IDs
  203. return (array) BackendModel::getDB()->getColumn(
  204. 'SELECT mci.cm_id
  205. FROM mailmotor_campaignmonitor_ids AS mci
  206. WHERE mci.type = ? AND mci.other_id IN (' . implode(',', $groupIds) . ')',
  207. array('list')
  208. );
  209. }
  210. /**
  211. * Returns the CM IDs for a given list of template IDs
  212. *
  213. * @param array $templateIds The ids of the templates.
  214. * @return array
  215. */
  216. public static function getCampaignMonitorIDsForTemplates($templateIds)
  217. {
  218. // check if templates are set,
  219. $templates = (empty($templateIds)) ? array(BackendMailmotorModel::getDefaultTemplateID()) : $templateIds;
  220. // fetch campaignmonitor IDs
  221. return (array) BackendModel::getDB()->getColumn(
  222. 'SELECT mci.cm_id
  223. FROM mailmotor_campaignmonitor_ids AS mci
  224. WHERE mci.type = ? AND mci.other_id IN (' . implode(',', $templates) . ')',
  225. array('template')
  226. );
  227. }
  228. /**
  229. * Returns the client ID from the settings
  230. *
  231. * @return string
  232. */
  233. public static function getClientID()
  234. {
  235. return (string) BackendModel::getModuleSetting('mailmotor', 'cm_client_id');
  236. }
  237. /**
  238. * Returns the clients for use in a dropdown
  239. *
  240. * @return array
  241. */
  242. public static function getClientsAsPairs()
  243. {
  244. // get the base stack of clients
  245. $clients = self::getCM()->getClients();
  246. // stop here if no clients were found
  247. if(empty($clients)) return array();
  248. // reserve results stack
  249. $results = array();
  250. $results[0] = SpoonFilter::ucfirst(BL::lbl('CreateNewClient', 'mailmotor'));
  251. // loop the clients
  252. foreach($clients as $client)
  253. {
  254. $results[$client['id']] = $client['name'];
  255. }
  256. return $results;
  257. }
  258. /**
  259. * Returns the CampaignMonitor object.
  260. *
  261. * @return CampaignMonitor
  262. */
  263. public static function getCM()
  264. {
  265. // campaignmonitor reference exists
  266. if(!Spoon::exists('campaignmonitor'))
  267. {
  268. // check if the CampaignMonitor class exists
  269. if(!SpoonFile::exists(PATH_LIBRARY . '/external/campaignmonitor.php'))
  270. {
  271. // the class doesn't exist, so throw an exception
  272. throw new SpoonFileException(BL::err('ClassDoesNotExist', 'mailmotor'));
  273. }
  274. // require CampaignMonitor class
  275. require_once 'external/campaignmonitor.php';
  276. // set login data
  277. $url = BackendModel::getModuleSetting('mailmotor', 'cm_url');
  278. $username = BackendModel::getModuleSetting('mailmotor', 'cm_username');
  279. $password = BackendModel::getModuleSetting('mailmotor', 'cm_password');
  280. // init CampaignMonitor object
  281. $cm = new CampaignMonitor($url, $username, $password, 60, self::getClientId());
  282. // set CampaignMonitor object reference
  283. Spoon::set('campaignmonitor', $cm);
  284. }
  285. return Spoon::get('campaignmonitor');
  286. }
  287. /**
  288. * Returns the CampaignMonitor countries as pairs
  289. *
  290. * @return array
  291. */
  292. public static function getCountriesAsPairs()
  293. {
  294. // get the countries
  295. $records = self::getCM()->getCountries();
  296. // loop and make em pairs
  297. foreach($records as &$record) $records[$record] = $record;
  298. // return the countries
  299. return $records;
  300. }
  301. /**
  302. * Returns the custom fields by a given group ID
  303. *
  304. * @param int $groupId The id of the group.
  305. * @return array
  306. */
  307. public static function getCustomFields($groupId)
  308. {
  309. // get CM ID for this group
  310. $listId = self::getCampaignMonitorID('list', $groupId);
  311. // get the custom fields from CM
  312. $cmFields = self::getCM()->getCustomFields($listId);
  313. // reserve new fields array
  314. $newFields = array();
  315. // fields found
  316. if(!empty($cmFields))
  317. {
  318. // get the custom fields from our database
  319. $fields = BackendMailmotorModel::getCustomFields($groupId);
  320. // loop the fields
  321. foreach($cmFields as $field)
  322. {
  323. // check if the field exists already. If not; add it
  324. if(!in_array($field['name'], $fields)) $fields[] = $field['name'];
  325. }
  326. // update the fields
  327. BackendMailmotorModel::updateCustomFields($fields, $groupId);
  328. }
  329. // return the results
  330. return (array) $fields;
  331. }
  332. /**
  333. * Returns what addresses opened a certain mailing
  334. *
  335. * @param string $cmId The id of the mailing in CampaignMonitor.
  336. * @param bool[optional] $getColumn If this is true, it will return an array with just the email addresses who opened the mailing.
  337. * @return array
  338. */
  339. public static function getMailingOpens($cmId, $getColumn = false)
  340. {
  341. // fetch the campaign opens from CM
  342. $records = self::getCM()->getCampaignOpens($cmId);
  343. // check we have records
  344. if(empty($records)) return false;
  345. // return the records
  346. if(!$getColumn) return (array) $records;
  347. // new result stack
  348. $results = array();
  349. // loop the records, save emails to new result stack
  350. foreach($records as $record) $results[] = $record['email'];
  351. // return the results
  352. return (array) $results;
  353. }
  354. /**
  355. * Get the custom field value for 'name'
  356. *
  357. * @param array $fields The custom fields array.
  358. * @return string
  359. */
  360. private static function getNameFieldValue($fields)
  361. {
  362. // check input
  363. $name = null;
  364. // set the name if it is present in the custom fields
  365. if(isset($fields['name'])) $name = $fields['name'];
  366. elseif(isset($fields['Name'])) $name = $fields['Name'];
  367. elseif(isset($fields[BL::lbl('Name')])) $name = $fields[BL::lbl('Name')];
  368. // return the value
  369. return $name;
  370. }
  371. /**
  372. * Returns the statistics for a given mailing
  373. *
  374. * @param int $id The id of the mailing.
  375. * @param bool[optional] $fetchClicks If the click-count should be included.
  376. * @param bool[optional] $fetchOpens If the open-count should be included.
  377. * @return array
  378. */
  379. public static function getStatistics($id, $fetchClicks = false, $fetchOpens = false)
  380. {
  381. // check if the mailing exists
  382. if(!BackendMailmotorModel::existsMailing($id)) throw new SpoonException('No mailing found for id ' . $id);
  383. // fetch cmID
  384. $cmId = self::getCampaignMonitorID('campaign', $id);
  385. // fetch the CM ID
  386. if($cmId)
  387. {
  388. // fetch the statistics
  389. $stats = self::getCM()->getCampaignSummary($cmId);
  390. // stop here if no recipients were found
  391. if($stats['recipients'] == 0) return false;
  392. // reset the bounces to match the real ones
  393. $bounces = BackendMailmotorCMHelper::getBounces($id);
  394. // re-calculate base stats to match CM's
  395. $stats['bounces'] = count($bounces);
  396. $stats['recipients'] = ($stats['recipients']);
  397. $stats['recipients_total'] = ($stats['recipients']);
  398. $stats['unopens'] = $stats['recipients'] - $stats['unique_opens'] - $stats['bounces'];
  399. $stats['clicks_total'] = 0;
  400. // add percentages to these stats
  401. $stats['bounces_percentage'] = ($stats['recipients'] == 0) ? 0 : floor(($stats['bounces'] / $stats['recipients_total']) * 100) . '%';
  402. $stats['recipients_percentage'] = ($stats['recipients'] == 0) ? 0 : ceil(($stats['recipients'] / $stats['recipients_total']) * 100) . '%';
  403. $stats['unique_opens_percentage'] = ($stats['recipients'] == 0) ? 0 : ceil(($stats['unique_opens'] / $stats['recipients']) * 100) . '%';
  404. $stats['unopens_percentage'] = ($stats['recipients'] == 0) ? 0 : floor(($stats['unopens'] / $stats['recipients']) * 100) . '%';
  405. $stats['clicks_percentage'] = ($stats['recipients'] == 0) ? 0 : ceil(($stats['clicks'] / $stats['recipients']) * 100) . '%';
  406. // fetch clicks or not?
  407. if($fetchClicks)
  408. {
  409. // get detailed click reports
  410. $subscriberClicks = self::getCM()->getCampaignClicks($cmId);
  411. // links have been clicked
  412. if(!empty($subscriberClicks))
  413. {
  414. // declare array
  415. $stats['clicked_links'] = array();
  416. $stats['clicked_links_by'] = $subscriberClicks;
  417. // filter out the clicked links
  418. foreach($subscriberClicks as $link => $clickers)
  419. {
  420. // count the clickers
  421. $clickerCount = count($clickers);
  422. $stats['clicked_links'][] = array('link' => $link, 'clicks' => $clickerCount);
  423. $stats['clicks_total'] += $clickerCount;
  424. }
  425. /*
  426. // re-loop so we can fix the keys
  427. foreach($stats['clicked_links'] as $link)
  428. {
  429. // store the link data
  430. $stats['clicked_links'][] = array('link' => urlencode($link['link']));
  431. // unset the record with the link as key
  432. unset($stats['clicked_links'][$link['link']]);
  433. }
  434. // re-loop so we can fix the keys
  435. foreach($stats['clicked_links_by'] as $link => $clicks)
  436. {
  437. // loop the clicks
  438. foreach($clicks as $click)
  439. {
  440. // store the link data
  441. $stats['clicked_links_by'][$link][] = array('email' => $click['email']);
  442. // unset the record with the link as key
  443. unset($stats['clicked_links_by'][$link][$click['email']]);
  444. }
  445. }
  446. */
  447. }
  448. }
  449. // fetch opened stats or not?
  450. if($fetchOpens)
  451. {
  452. // fetch opens
  453. $stats['opens'] = self::getMailingOpens($cmId);
  454. }
  455. // return the results
  456. return $stats;
  457. }
  458. // at this point, return false
  459. return false;
  460. }
  461. /**
  462. * Returns the statistics for a given e-mail address
  463. *
  464. * @param string $email The emailaddress to get the stats for.
  465. * @return array
  466. */
  467. public static function getStatisticsByAddress($email)
  468. {
  469. // reserve statistics array
  470. $stats = array();
  471. $stats['recipients'] = 0;
  472. $stats['opens'] = 0;
  473. $stats['unique_opens'] = 0;
  474. $stats['clicks'] = 0;
  475. $stats['unsubscribes'] = 0;
  476. $stats['bounces'] = 0;
  477. $stats['recipients_total'] = 0;
  478. $stats['unopens'] = 0;
  479. // fetch all mailings in this campaign
  480. $mailings = BackendModel::getDB()->getRecords(BackendMailmotorModel::QRY_DATAGRID_BROWSE_SENT_FOR_CAMPAIGN, array('sent', $email));
  481. // no mailings found
  482. if(empty($mailings)) return array();
  483. // loop the mailings
  484. foreach($mailings as $mailing)
  485. {
  486. // store the statistics in a separate array
  487. $mailingStats = self::getStatistics($mailing['id']);
  488. // add all stats to the totals
  489. $stats['recipients'] += $mailingStats['recipients'];
  490. $stats['opens'] += $mailingStats['opens'];
  491. $stats['unique_opens'] += $mailingStats['unique_opens'];
  492. $stats['clicks'] += $mailingStats['clicks'];
  493. $stats['unsubscribes'] += $mailingStats['unsubscribes'];
  494. $stats['bounces'] += $mailingStats['bounces'];
  495. $stats['recipients_total'] += $mailingStats['recipients_total'];
  496. $stats['unopens'] += $mailingStats['unopens'];
  497. }
  498. // add percentages to these stats
  499. $stats['bounces_percentage'] = floor(($stats['bounces'] / $stats['recipients_total']) * 100) . '%';
  500. $stats['recipients_percentage'] = ceil(($stats['recipients'] / $stats['recipients_total']) * 100) . '%';
  501. $stats['unique_opens_percentage'] = ceil(($stats['unique_opens'] / $stats['recipients']) * 100) . '%';
  502. $stats['unopens_percentage'] = floor(($stats['unopens'] / $stats['recipients']) * 100) . '%';
  503. $stats['clicks_percentage'] = ceil(($stats['clicks'] / $stats['recipients']) * 100) . '%';
  504. // return the stats
  505. return (array) $stats;
  506. }
  507. /**
  508. * Returns the statistics for all mailings in a given campaign
  509. *
  510. * @param int $id The id of the campaign.
  511. * @return array
  512. */
  513. public static function getStatisticsByCampaignID($id)
  514. {
  515. // reserve statistics array
  516. $stats = array();
  517. $stats['recipients'] = 0;
  518. $stats['opens'] = 0;
  519. $stats['unique_opens'] = 0;
  520. $stats['clicks'] = 0;
  521. $stats['unsubscribes'] = 0;
  522. $stats['bounces'] = 0;
  523. $stats['recipients_total'] = 0;
  524. $stats['unopens'] = 0;
  525. // fetch all mailings in this campaign
  526. $mailings = BackendModel::getDB()->getRecords(BackendMailmotorModel::QRY_DATAGRID_BROWSE_SENT_FOR_CAMPAIGN, array('sent', $id));
  527. // no mailings found
  528. if(empty($mailings)) return array();
  529. // loop the mailings
  530. foreach($mailings as $mailing)
  531. {
  532. // store the statistics in a separate array
  533. $mailingStats = self::getStatistics($mailing['id'], false);
  534. // add all stats to the totals
  535. $stats['recipients'] += $mailingStats['recipients'];
  536. $stats['opens'] += $mailingStats['opens'];
  537. $stats['unique_opens'] += $mailingStats['unique_opens'];
  538. $stats['clicks'] += $mailingStats['clicks'];
  539. $stats['unsubscribes'] += $mailingStats['unsubscribes'];
  540. $stats['bounces'] += $mailingStats['bounces'];
  541. $stats['recipients_total'] += $mailingStats['recipients_total'];
  542. $stats['unopens'] += $mailingStats['unopens'];
  543. }
  544. // add percentages to these stats
  545. $stats['bounces_percentage'] = floor(($stats['bounces'] / $stats['recipients_total']) * 100) . '%';
  546. $stats['recipients_percentage'] = ceil(($stats['recipients'] / $stats['recipients_total']) * 100) . '%';
  547. $stats['unique_opens_percentage'] = ceil(($stats['unique_opens'] / $stats['recipients']) * 100) . '%';
  548. $stats['unopens_percentage'] = floor(($stats['unopens'] / $stats['recipients']) * 100) . '%';
  549. $stats['clicks_percentage'] = ceil(($stats['clicks'] / $stats['recipients']) * 100) . '%';
  550. return (array) $stats;
  551. }
  552. /**
  553. * Returns all subscribers, regardless of the page limit CM gives us.
  554. *
  555. * @param string $listId The list ID to get the subscribers from.
  556. * @return array
  557. */
  558. public static function getSubscribers($listId)
  559. {
  560. // get list statistics, so we can obtain the total subscribers for this list
  561. $listStats = self::getCM()->getListStatistics($listId);
  562. // pagecount is calculated by getting the total amount of subscribers divided by 1k, which is the return limit for CM's getSubscribers()
  563. $pageCount = (int) ceil($listStats['total_subscribers'] / 1000);
  564. // reserve a result stack
  565. $results = array();
  566. // check if we have at least 1 page
  567. if($listStats['total_subscribers'] !== 0)
  568. {
  569. // set the pagecount to 1 by default
  570. $pageCount++;
  571. // loop the total amount of pages and fetch the subscribers accordingly
  572. for($i = $pageCount; $i != 0; $i--)
  573. {
  574. // get the subscribers
  575. $subscribers = self::getCM()->getSubscribers($listId, null, $i, 1000);
  576. // add the subscribers to the result stack
  577. $results = array_merge($results, $subscribers);
  578. }
  579. }
  580. return $results;
  581. }
  582. /**
  583. * Returns the CampaignMonitor countries as pairs
  584. *
  585. * @return array
  586. */
  587. public static function getTimezonesAsPairs()
  588. {
  589. // get the timezones
  590. $records = self::getCM()->getTimezones();
  591. // loop and make em pairs
  592. foreach($records as &$record) $records[$record] = $record;
  593. // return the timezones
  594. return $records;
  595. }
  596. /**
  597. * Inserts a record into the mailmotor_campaignmonitor_ids table
  598. *
  599. * @param string $type The type of the record.
  600. * @param string $id The id in CampaignMonitor.
  601. * @param string $otherId The id in our tables.
  602. * @return string
  603. */
  604. public static function insertCampaignMonitorID($type, $id, $otherId)
  605. {
  606. // check input
  607. $type = SpoonFilter::getValue($type, array('campaign', 'list', 'template'), '');
  608. // no valid type given
  609. if($type == '') throw new CampaignMonitorException('No valid CM ID type given (only campaign, list, template).');
  610. // insert the campaignmonitor ID
  611. BackendModel::getDB(true)->insert('mailmotor_campaignmonitor_ids', array('type' => $type, 'cm_id' => $id, 'other_id' => $otherId));
  612. }
  613. /**
  614. * Creates a list in campaignmonitor and inserts the group record in the database. Returns the group ID
  615. *
  616. * @param array $item The group record to insert.
  617. * @return int
  618. */
  619. public static function insertGroup(array $item)
  620. {
  621. // build unsubscribe link for this list
  622. $unsubscribeLink = SITE_URL . BackendModel::getURLForBlock('mailmotor', 'unsubscribe', BL::getWorkingLanguage());
  623. // predict the next insert ID for the mailmotor_groups table
  624. $groupId = BackendMailmotorModel::getMaximumIdForGroups() + 1;
  625. // create list
  626. $cmId = self::getCM()->createList($item['name'], $unsubscribeLink . '/?group=' . $groupId . '&email=[email]');
  627. // a list was created
  628. if($cmId)
  629. {
  630. // check if we have a default group set
  631. if($item['is_default'] === 'Y' && $item['language'] != '0')
  632. {
  633. // set all defaults to N.
  634. BackendModel::getDB(true)->update('mailmotor_groups', array('is_default' => 'N', 'language' => null), 'language = ?', $item['language']);
  635. }
  636. // insert in database
  637. $id = BackendMailmotorModel::insertGroup($item);
  638. // insert in campaignmonitor
  639. self::insertCampaignMonitorID('list', $cmId, $id);
  640. // return the group ID
  641. return (int) $id;
  642. }
  643. }
  644. /**
  645. * Creates a campaign in campaignmonitor. Returns the campaign ID
  646. *
  647. * @param array $item The mailing record to insert.
  648. * @return mixed
  649. */
  650. public static function insertMailing(array $item)
  651. {
  652. // create campaign in CM
  653. $cmId = self::getCM()->createCampaign($item['name'], $item['subject'], $item['from_name'], $item['from_email'], $item['reply_to_email'], $item['content_html_url'], $item['content_plain_url'], $item['group_cm_ids']);
  654. // a campaign was created
  655. if($cmId)
  656. {
  657. // insert in campaignmonitor
  658. self::insertCampaignMonitorID('campaign', $cmId, $item['id']);
  659. // return the campaign CM ID
  660. return $cmId;
  661. }
  662. // no campaign created at this point
  663. return false;
  664. }
  665. /**
  666. * Creates a campaign draft into campaignmonitor.
  667. *
  668. * @param array $item The mailing record to update a campaign draft.
  669. * @return string The campaign ID of the newly created draft.
  670. */
  671. public static function insertMailingDraft(array $item)
  672. {
  673. // get the preview URLs, so CM knows where to get the HTML/plaintext content
  674. $item['content_html_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'html', true);
  675. $item['content_plain_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'plain', true);
  676. // get the CM IDs for all groups linked to the mailing record
  677. if(!isset($item['group_cm_ids']))
  678. {
  679. $item['group_cm_ids'] = self::getCampaignMonitorIDsForGroups($item['groups']);
  680. }
  681. // create the campaign ID, and obtain the campaign CM ID
  682. $campaignID = self::getCM()->createCampaign(
  683. // if we add a timestamp to the name, we won't get the duplicate campaign name errors.
  684. $item['name'] . ' - ' . time(),
  685. $item['subject'],
  686. $item['from_name'],
  687. $item['from_email'],
  688. $item['reply_to_email'],
  689. $item['content_html_url'],
  690. $item['content_plain_url'],
  691. $item['group_cm_ids']
  692. );
  693. // if we received a valid CM ID, insert the CM ID in the database
  694. if(is_string($campaignID))
  695. {
  696. self::insertCampaignMonitorID('campaign', $campaignID, $item['id']);
  697. }
  698. // return the campaign CM ID
  699. return $campaignID;
  700. }
  701. /**
  702. * Saves a draft mailing into campaignmonitor
  703. *
  704. * @param array $item The mailing record to create/update a campaign draft.
  705. * @return string The newly created campaignmonitor ID
  706. */
  707. public static function saveMailingDraft(array $item)
  708. {
  709. // get the campaignmonitor ID for campaign
  710. $campaignID = self::getCampaignMonitorID('campaign', $item['id']);
  711. // either insert/update a draft, depends if we found a valid campaign ID or not
  712. if(!$campaignID)
  713. {
  714. return self::insertMailingDraft($item);
  715. }
  716. else
  717. {
  718. return self::updateMailingDraft($item);
  719. }
  720. }
  721. /**
  722. * Creates a campaign in campaignmonitor and sends it
  723. *
  724. * @param array $item The mailing record to insert.
  725. */
  726. public static function sendMailing($item)
  727. {
  728. // get db
  729. $db = BackendModel::getDB(true);
  730. // fetch the CM IDs for each group if this field is not set yet
  731. if(!isset($item['group_cm_ids'])) $item['group_cm_ids'] = self::getCampaignMonitorIDsForGroups($item['groups']);
  732. // fetch the content URLs
  733. if(!isset($item['content_html_url'])) $item['content_html_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'html', true);
  734. if(!isset($item['content_plain_url'])) $item['content_plain_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'plain', true);
  735. // at this point $result should equal the CM ID, so let's attempt to send it
  736. self::getCM()->sendCampaign($item['cm_id'], $item['from_email'], $item['delivery_date']);
  737. }
  738. /**
  739. * Creates a campaign in campaignmonitor and sends it
  740. *
  741. * @param int $id The ID of the mailing
  742. * @param string $recipient The e-mail address to send a preview mailing to.
  743. */
  744. public static function sendPreviewMailing($id, $recipient)
  745. {
  746. $campaignID = self::getCampaignMonitorID('campaign', $id);
  747. self::getCM()->sendCampaignPreview($campaignID, $recipient);
  748. }
  749. /**
  750. * Subscribes an e-mail address and send him/her to CampaignMonitor
  751. *
  752. * @param string $email The emailaddress.
  753. * @param string[optional] $groupId The group wherin the emailaddress should be added.
  754. * @param array[optional] $customFields Any optional custom fields.
  755. * @return bool
  756. */
  757. public static function subscribe($email, $groupId = null, $customFields = null)
  758. {
  759. // get objects
  760. $db = BackendModel::getDB(true);
  761. $cm = self::getCM();
  762. // set groupID
  763. $groupId = !empty($groupId) ? $groupId : BackendMailmotorModel::getDefaultGroupID();
  764. // get group CM ID
  765. $groupCMId = self::getCampaignMonitorID('list', $groupId);
  766. // see if the name is present in the custom fields
  767. $name = self::getNameFieldValue($customFields);
  768. // group ID found
  769. if(BackendMailmotorModel::existsGroup($groupId) && $cm->subscribe($email, $name, $customFields, true, $groupCMId))
  770. {
  771. // set variables
  772. $subscriber['email'] = $email;
  773. $subscriber['source'] = 'CMS';
  774. $subscriber['created_on'] = BackendModel::getUTCDate('Y-m-d H:i:s');
  775. // insert/update the user
  776. $db->execute('INSERT INTO mailmotor_addresses(email, source, created_on)
  777. VALUES (?, ?, ?)
  778. ON DUPLICATE KEY UPDATE source = ?, created_on = ?',
  779. array($subscriber['email'], $subscriber['source'], $subscriber['created_on'],
  780. $subscriber['source'], $subscriber['created_on']));
  781. // set variables
  782. $subscriberGroup['email'] = $email;
  783. $subscriberGroup['group_id'] = $groupId;
  784. $subscriberGroup['status'] = 'subscribed';
  785. $subscriberGroup['subscribed_on'] = BackendModel::getUTCDate('Y-m-d H:i:s');
  786. // insert/update the user
  787. $db->execute(
  788. 'INSERT INTO mailmotor_addresses_groups(email, group_id, status, subscribed_on)
  789. VALUES (?, ?, ?, ?)
  790. ON DUPLICATE KEY UPDATE group_id = ?, status = ?, subscribed_on = ?',
  791. array(
  792. $subscriberGroup['email'],
  793. $subscriberGroup['group_id'],
  794. $subscriberGroup['status'],
  795. $subscriberGroup['subscribed_on'],
  796. $subscriberGroup['group_id'],
  797. $subscriberGroup['status'],
  798. $subscriberGroup['subscribed_on']
  799. )
  800. );
  801. // update custom fields for this subscriber/group
  802. if(!empty($customFields)) BackendMailmotorModel::updateCustomFields($customFields, $groupId, $email);
  803. // user subscribed
  804. return true;
  805. }
  806. // user not subscribed
  807. return false;
  808. }
  809. /**
  810. * Unsubscribes an e-mail address from CampaignMonitor and our database
  811. *
  812. * @param string $email The emailaddress to unsubscribe.
  813. * @param string[optional] $groupId The group wherefrom the emailaddress should be unsubscribed.
  814. * @return bool
  815. */
  816. public static function unsubscribe($email, $groupId = null)
  817. {
  818. // get objects
  819. $cm = self::getCM();
  820. // set group ID
  821. $groupId = !empty($groupId) ? $groupId : BackendMailmotorModel::getDefaultGroupID();
  822. // get group CM ID
  823. $groupCMId = self::getCampaignMonitorID('list', $groupId);
  824. // group exists
  825. if(BackendMailmotorModel::existsGroup($groupId))
  826. {
  827. // unsubscribe the email from this group
  828. self::getCM()->unsubscribe($email, $groupCMId);
  829. // set variables
  830. $subscriber = array();
  831. $subscriber['status'] = 'unsubscribed';
  832. $subscriber['unsubscribed_on'] = BackendModel::getUTCDate('Y-m-d H:i:s');
  833. // unsubscribe the user
  834. BackendModel::getDB(true)->update('mailmotor_addresses_groups', $subscriber, 'email = ? AND group_id = ?', array($email, $groupId));
  835. // user unsubscribed
  836. return true;
  837. }
  838. // user not unsubscribed
  839. return false;
  840. }
  841. /**
  842. * Updates a client
  843. *
  844. * @param string $companyName The client company name.
  845. * @param string $contactName The personal name of the principle contact for this client.
  846. * @param string $email An email address to which this client will be sent application-related emails.
  847. * @param string[optional] $country This client’s country.
  848. * @param string[optional] $timezone Client timezone for tracking and reporting data.
  849. */
  850. public static function updateClient($companyName, $contactName, $email, $country = 'Belgium', $timezone = '(GMT+01:00) Brussels, Copenhagen, Madrid, Paris')
  851. {
  852. self::getCM()->updateClientBasics($companyName, $contactName, $email, $country, $timezone);
  853. }
  854. /**
  855. * Updates a list with campaignmonitor and in the database. Returns the affected rows
  856. *
  857. * @param array $item The new data.
  858. * @return int
  859. */
  860. public static function updateGroup($item)
  861. {
  862. // build unsubscribe link for this list
  863. $unsubscribeLink = SITE_URL . BackendModel::getURLForBlock('mailmotor', 'unsubscribe', BL::getWorkingLanguage());
  864. // update the group with CM
  865. self::getCM()->updateList($item['name'], $unsubscribeLink . '/?group=' . $item['id'] . '&email=[email]', null, null, self::getCampaignMonitorID('list', $item['id']));
  866. // check if we have a default group set
  867. if($item['is_default'] === 'Y' && $item['language'] != '0')
  868. {
  869. // set all defaults to N
  870. BackendModel::getDB(true)->update('mailmotor_groups', array('is_default' => 'N', 'language' => null), 'language = ?', array($item['language']));
  871. }
  872. // update the group in our database
  873. return (int) BackendMailmotorModel::updateGroup($item);
  874. }
  875. /**
  876. * Updates a mailing
  877. *
  878. * @param array $item The mailing record to update.
  879. */
  880. public static function updateMailing(array $item)
  881. {
  882. // local item
  883. $local = $item;
  884. // delete the mailing
  885. self::deleteMailings($item['id']);
  886. // fetch the CM IDs for each group if this field is not set yet
  887. if(!isset($item['group_cm_ids'])) $item['group_cm_ids'] = self::getCampaignMonitorIDsForGroups($item['groups']);
  888. // fetch the content URLs
  889. if(!isset($item['content_html_url'])) $item['content_html_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'html', true);
  890. if(!isset($item['content_plain_url'])) $item['content_plain_url'] = BackendMailmotorModel::getMailingPreviewURL($item['id'], 'plain', true);
  891. // overwrite the name, because the previous one is taken -.-
  892. $item['name'] .= ' (#' . rand(0, 999) . ')';
  893. // re-insert the mailing in CM
  894. self::insertMailing($item);
  895. // unset vars we don't need, save vars we need later
  896. $groups = $local['groups'];
  897. unset($local['cm_id'], $local['groups'], $local['recipients'], $local['delivery_date']);
  898. // serialize full content mailing
  899. $local['data'] = serialize($local['data']);
  900. // re-insert the mailing in our database
  901. $id = BackendMailmotorModel::insertMailing($local);
  902. // reinsert the groups for this mailing
  903. BackendMailmotorModel::updateGroupsForMailing($id, $groups);
  904. }
  905. /**
  906. * "Updates" a mailing draft; it deletes and re-creates a draft mailing.
  907. * Campaignmonitor does not have an updateDraft method, so we have to do it this way in order
  908. * to be able to use their sendCampaignPreview method.
  909. *
  910. * @param array $item The mailing record to update a campaign draft.
  911. * @return mixed Returns the newly made campaign ID, or false if the method failed.
  912. */
  913. public static function updateMailingDraft(array $item)
  914. {
  915. // get the DB
  916. $db = BackendModel::getDB(true);
  917. // get the CM campaign ID for this campaign
  918. $campaignID = self::getCampaignMonitorID('campaign', $item['id']);
  919. // if the campaign ID
  920. if(is_string($campaignID))
  921. {
  922. // first we insert the new campaign draft and store the CM ID
  923. $newCampaignID = self::insertMailingDraft($item);
  924. // delete the old CM campaign
  925. self::getCM()->deleteCampaign($campaignID);
  926. // remove the old CM ID from the database
  927. $db->delete('mailmotor_campaignmonitor_ids', 'cm_id = ?', $campaignID);
  928. // return the CM ID for the newly created draft campaign
  929. return $newCampaignID;
  930. }
  931. }
  932. }