/app/Stats.php

https://github.com/tortuvshin/newsfeed · PHP · 145 lines · 85 code · 20 blank · 40 comment · 18 complexity · 7db42d8786206dd480376368789a315d MD5 · raw file

  1. <?php
  2. namespace App;
  3. use Illuminate\Database\Eloquent\Model;
  4. class Stats extends Model
  5. {
  6. protected $table = 'popularity_stats';
  7. protected $fillable = ['trackable_id', 'trackable_type', 'one_day_stats', 'seven_days_stats', 'thirty_days_stats', 'all_time_stats','raw_stats'];
  8. public function setRawStatsAttribute($value)
  9. {
  10. $this->attributes['raw_stats'] = serialize($value);
  11. }
  12. public function getRawStatsAttribute($value)
  13. {
  14. return unserialize($value);
  15. }
  16. /**
  17. * Polymorphic relation
  18. */
  19. public function trackable()
  20. {
  21. return $this->morphTo();
  22. }
  23. /**
  24. * Increments hits for a certain date and its previous days.
  25. *
  26. * @param String $date expects a date with format Y-m-d or uses current date if null
  27. * @return boolean updated stats success or not
  28. */
  29. public function updateStats($date = null)
  30. {
  31. //checks for a valid date format
  32. if( !empty($date) && !self::validDateFormat($date)) {
  33. return false;
  34. }
  35. $date = empty($date) ? gmdate('Y-m-d') : $date;
  36. $raw_stats = $this->raw_stats;
  37. // Update model with new stats
  38. $this->one_day_stats = $this->_calculate_days_stats( 1 , $raw_stats, $date );
  39. $this->seven_days_stats = $this->_calculate_days_stats( 7 , $raw_stats, $date );
  40. $this->thirty_days_stats = $this->_calculate_days_stats( 30, $raw_stats, $date );
  41. $this->all_time_stats = $this->all_time_stats + 1;
  42. // Update raw_stats for date
  43. if ( isset( $raw_stats ) && count( $raw_stats ) >= 30 ) {
  44. // remove older than 30 days stats
  45. array_shift( $raw_stats );
  46. // add new date
  47. $raw_stats[$date] = 1;
  48. } else {
  49. if ( ! isset( $raw_stats[$date] ) ) {
  50. $raw_stats[$date] = 1;
  51. } else {
  52. $raw_stats[$date] = $raw_stats[$date]+1;
  53. }
  54. }
  55. $this->raw_stats = $raw_stats;
  56. return $this->save();
  57. }
  58. /**
  59. * Calculates hits for each date in a range of $days from $date
  60. *
  61. * @param integer $days number of days to increment hits
  62. * @param array $existing_stats array of date => hits paired values
  63. * @param string $date base date
  64. * @return integer number of hits
  65. */
  66. private function _calculate_days_stats( $days, $existing_stats, $date ) {
  67. if ( $existing_stats && $days == 1 ){
  68. if ( isset( $existing_stats[$date] ) ) {
  69. return (int)$existing_stats[$date] + 1;
  70. }
  71. }else if ( $existing_stats ) {
  72. $extra_to_add = 0;
  73. if ( isset( $existing_stats[$date] ) ) {
  74. $extra_to_add = (int)$existing_stats[$date];
  75. }
  76. $total = 0;
  77. for ( $i = 1; $i < $days; $i++ ) {
  78. $timestampDate = strtotime($date);
  79. // calculate relative date to provided $date
  80. $old_date = date('Y-m-d', strtotime( "-{$i} days" , $timestampDate ) );
  81. if ( isset( $existing_stats[$old_date] ) ) {
  82. $total += (int)$existing_stats[$old_date];
  83. }
  84. }
  85. return $total + $extra_to_add + 1;
  86. }
  87. return 1;
  88. }
  89. /**
  90. * Checks for a string with a date format Y-m-d
  91. *
  92. * @param string $date
  93. * @return boolean is valid or not
  94. */
  95. private function validDateFormat($date)
  96. {
  97. $result = \DateTime::createFromFormat('Y-m-d', $date) !== FALSE;
  98. return $result;
  99. }
  100. /**
  101. * Get the query builder object for the Stats model's table prepared with the requested items,
  102. * ordered by one of the stats column.
  103. *
  104. * @param $days String one_day_stats|seven_days_stats|thirty_days_stats|all_time_stats
  105. * @param $orderType String ASC|DESC
  106. * @param $modelType String Filter by this Eloquent Model type
  107. * @param $limit int Number of items to return
  108. * @return \Illuminate\Database\Eloquent\Builder
  109. */
  110. public function scopeGetStats($query, $days = 'one_day_stats', $orderType = 'DESC', $modelType = '', $limit = null)
  111. {
  112. if( !empty( $modelType )){
  113. $query->where( 'trackable_type', '=', $modelType );
  114. }
  115. // Only retrieve elements with at least 1 hit in the requested period
  116. if( !empty( $days )){
  117. $query->where( $days, '!=', 0 );
  118. }
  119. if( !empty( $limit )){
  120. $query->take($limit);
  121. }
  122. $query->orderBy( $days, $orderType );
  123. return $query;
  124. }
  125. }