PageRenderTime 62ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

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

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