PageRenderTime 47ms CodeModel.GetById 21ms RepoModel.GetById 1ms app.codeStats 0ms

/webapp/plugins/insightsgenerator/insights/outreachpunchcard.php

https://github.com/SimonCoopey/ThinkUp
PHP | 225 lines | 158 code | 29 blank | 38 comment | 13 complexity | c6e4c4e585ac4c33d6aaf755e67aa694 MD5 | raw file
  1. <?php
  2. /*
  3. Plugin Name: Outreach Punchcard
  4. Description: What times of day your posts get the biggest reaction.
  5. When: 7th for Twitter, 14th for Facebook, 23rd for Instagram
  6. */
  7. /**
  8. *
  9. * ThinkUp/webapp/plugins/insightsgenerator/insights/outreachpunchcard.php
  10. *
  11. * Copyright (c) 2013 Nilaksh Das, Gina Trapani
  12. *
  13. * LICENSE:
  14. *
  15. * This file is part of ThinkUp (http://thinkup.com).
  16. *
  17. * ThinkUp is free software: you can redistribute it and/or modify it under the terms of the GNU General Public
  18. * License as published by the Free Software Foundation, either version 2 of the License, or (at your option) any
  19. * later version.
  20. *
  21. * ThinkUp is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied
  22. * warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
  23. * details.
  24. *
  25. * You should have received a copy of the GNU General Public License along with ThinkUp. If not, see
  26. * <http://www.gnu.org/licenses/>.
  27. *
  28. * @license http://www.gnu.org/licenses/gpl.html
  29. * @copyright 2013 Nilaksh Das, Gina Trapani
  30. * @author Nilaksh Das <nilakshdas [at] gmail [dot] com>
  31. */
  32. class OutreachPunchcardInsight extends InsightPluginParent implements InsightPlugin {
  33. /**
  34. * Slug for this insight
  35. **/
  36. var $slug = 'outreach_punchcard';
  37. public function generateInsight(Instance $instance, User $user, $last_week_of_posts, $number_days) {
  38. parent::generateInsight($instance, $user, $last_week_of_posts, $number_days);
  39. $this->logger->logInfo("Begin generating insight", __METHOD__.','.__LINE__);
  40. $since_date = date("Y-m-d");
  41. $filename = basename(__FILE__, ".php");
  42. $regenerate = false;
  43. switch ($instance->network) {
  44. case 'twitter':
  45. $day_of_month = 7;
  46. break;
  47. case 'facebook':
  48. $day_of_month = 14;
  49. break;
  50. case 'instagram':
  51. $day_of_month = 23;
  52. break;
  53. default:
  54. $day_of_month = 23;
  55. }
  56. $should_generate_insight = self::shouldGenerateMonthlyInsight($this->slug, $instance,
  57. $insight_date=$since_date, $regenerate_existing_insight=$regenerate, $day_of_month = $day_of_month,
  58. $count_related_posts=null, $excluded_networks=null, $enable_bonus_alternate_day = true);
  59. if ($should_generate_insight) {
  60. $this->logger->logInfo("Should generate", __METHOD__.','.__LINE__);
  61. $owner_instance_dao = DAOFactory::getDAO('OwnerInstanceDAO');
  62. $owner_dao = DAOFactory::getDAO('OwnerDAO');
  63. $owner_instance = $owner_instance_dao->getByInstance($instance->id);
  64. $owner_id = $owner_instance[0]->owner_id;
  65. $owner = $owner_dao->getById($owner_instance[0]->owner_id);
  66. try {
  67. $owner_timezone = new DateTimeZone($owner->timezone);
  68. } catch (Exception $e) {
  69. // In the odd case the owner has no or a malformed timezone
  70. $cfg = Config::getInstance();
  71. $owner_timezone = new DateTimeZone($cfg->getValue('timezone'));
  72. }
  73. $now = new DateTime();
  74. $offset = timezone_offset_get($owner_timezone, $now);
  75. $post_dao = DAOFactory::getDAO('PostDAO');
  76. $last_months_posts = $post_dao->getAllPostsByUsernameOrderedBy($instance->network_username,
  77. $instance->network, $count=null, $order_by="pub_date", $in_last_x_days = 30,
  78. $iterator = false, $is_public = false);
  79. $punchcard = array();
  80. $responses_chron = array();
  81. $response_avg_timediffs = array();
  82. for ($hotd = 0; $hotd < 24; $hotd++) {
  83. for ($dotm = 1; $dotm <= 30; $dotm++) {
  84. $punchcard['posts'][$dotm][$hotd] = 0;
  85. $punchcard['responses'][$dotm][$hotd] = 0;
  86. }
  87. $responses_chron[$hotd] = 0;
  88. }
  89. // $this->logger->logInfo("Last month's posts: ".Utils::varDumpToString($last_months_posts),
  90. // __METHOD__.','.__LINE__);
  91. if ($instance->network !== 'instagram') { //count replies and retweets
  92. foreach ($last_months_posts as $post) {
  93. $responses = array();
  94. $responses = array_merge(
  95. (array)$post_dao->getRepliesToPost($post->post_id, $post->network),
  96. (array)$post_dao->getRetweetsOfPost($post->post_id, $post->network)
  97. );
  98. foreach ($responses as $response) {
  99. $response_pub_date = new DateTime($response->pub_date);
  100. $response_dotm = date('j', (date('U', strtotime($response->pub_date)+$offset))); // Day of month
  101. $response_hotd = date('G', (date('U', strtotime($response->pub_date)+$offset))); // Hour of day
  102. $punchcard['responses'][$response_dotm][$response_hotd]++;
  103. $responses_chron[$response_hotd]++;
  104. }
  105. $post_pub_date = new DateTime($post->pub_date);
  106. $post_dotm = date('j', (date('U', strtotime($post->pub_date)+$offset))); // Day of the month
  107. $post_hotd = date('G', (date('U', strtotime($post->pub_date)+$offset))); // Hour of the day
  108. $punchcard['posts'][$post_dotm][$post_hotd]++;
  109. }
  110. } else { //count likes
  111. foreach ($last_months_posts as $post) {
  112. $post_pub_date = new DateTime($post->pub_date);
  113. $post_dotm = date('j', (date('U', strtotime($post->pub_date)+$offset))); // Day of month
  114. $post_hotd = date('G', (date('U', strtotime($post->pub_date)+$offset))); // Hour of day
  115. $punchcard['responses'][$post_dotm][$post_hotd]++;
  116. //$this->logger->logInfo("HOTD: ".$post_hotd, __METHOD__.','.__LINE__);
  117. $responses_chron[$post_hotd] += $post->favlike_count_cache;
  118. $punchcard['posts'][$post_dotm][$post_hotd]++;
  119. }
  120. }
  121. arsort($responses_chron);
  122. $most_responses = each($responses_chron);
  123. $insight_text = '';
  124. if ($most_responses['value'] > 2) {
  125. $time1_low_hotd = $most_responses['key'];
  126. $time1_high_hotd = $time1_low_hotd + 1;
  127. $time1_low = (($time1_low_hotd % 12) ? ($time1_low_hotd % 12) : 12)
  128. .((floor($time1_low_hotd / 12) == 1) ? 'pm' : 'am');
  129. $time1_high = (($time1_high_hotd % 12) ? ($time1_high_hotd % 12) : 12)
  130. .((floor($time1_high_hotd / 12) == 1) ? 'pm' : 'am');
  131. $plural = $most_responses['value']==1 ? InsightTerms::SINGULAR : InsightTerms::PLURAL;
  132. if ($instance->network == 'instagram') {
  133. $insight_text = "In the past month, what ". $this->username." posted "
  134. ."between <strong>".$time1_low." and ".$time1_high
  135. ."</strong> on Instagram got the most love - " .$most_responses['value']
  136. . " " .$this->terms->getNoun('like', $plural) . " in all.";
  137. } else {
  138. $insight_text = "In the past month, ". $this->username."'s "
  139. . $this->terms->getNoun('post', InsightTerms::PLURAL)
  140. ." got the biggest response between <strong>".$time1_low." and ".$time1_high."</strong> - "
  141. . $most_responses['value']." "
  142. . $this->terms->getNoun('reply', $plural) . " in all.";
  143. }
  144. // $this->logger->logInfo("Responses chron: ".Utils::varDumpToString($responses_chron),
  145. // __METHOD__.','.__LINE__);
  146. foreach ($responses_chron as $key => $value) {
  147. if ($value > 0 && $value < $most_responses['value']) {
  148. $time2_low_hotd = $key;
  149. $time2_high_hotd = $time2_low_hotd + 1;
  150. $time2_low = (($time2_low_hotd % 12) ? ($time2_low_hotd % 12) : 12)
  151. .((floor($time2_low_hotd / 12) == 1) ? 'pm' : 'am');
  152. $time2_high = (($time2_high_hotd % 12) ? ($time2_high_hotd % 12) : 12)
  153. .((floor($time2_high_hotd / 12) == 1) ? 'pm' : 'am');
  154. if ($instance->network == 'instagram') {
  155. $response_text = ($value > 1 ? 'hearts' : 'heart');
  156. } else {
  157. $response_text = ($value > 1 ? 'responses' : 'response');
  158. }
  159. $comparison_text = " That's compared to ".$value." "
  160. .$response_text ." between ".$time2_low." and ".$time2_high.". ";
  161. }
  162. }
  163. $insight_text .= $comparison_text;
  164. $headline = $this->username."'s best time is around " . $time1_low;
  165. $optimal_hour = substr($time1_low, 0, -2);
  166. //Instantiate the Insight object
  167. $my_insight = new Insight();
  168. //REQUIRED: Set the insight's required attributes
  169. $my_insight->instance_id = $instance->id;
  170. $my_insight->slug = $this->slug; //slug to label this insight's content
  171. $my_insight->date = $this->insight_date; //date of the data this insight applies to
  172. $my_insight->headline = $headline;
  173. $my_insight->text = $insight_text;
  174. $my_insight->header_image = '';
  175. $my_insight->emphasis = Insight::EMPHASIS_HIGH;
  176. $my_insight->filename = basename(__FILE__, ".php");
  177. // $my_insight->related_data = $punchcard;
  178. $my_insight->related_data = $optimal_hour;
  179. $this->insight_dao->insertInsight($my_insight);
  180. } else {
  181. $this->logger->logInfo("No insight: Most responses is ".Utils::varDumpToString($most_responses),
  182. __METHOD__.','.__LINE__);
  183. }
  184. }
  185. $this->logger->logInfo("Done generating insight", __METHOD__.','.__LINE__);
  186. }
  187. }
  188. $insights_plugin_registrar = PluginRegistrarInsights::getInstance();
  189. $insights_plugin_registrar->registerInsightPlugin('OutreachPunchcardInsight');