Completed
Pull Request — master (#163)
by Corey
02:32
created

UserBehavior::getCheckinBreakdown()   A

Complexity

Conditions 3
Paths 2

Size

Total Lines 19
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 10
dl 0
loc 19
rs 9.9332
c 0
b 0
f 0
cc 3
nc 2
nop 1
1
<?php
2
3
namespace common\models;
4
5
use Yii;
6
use \common\interfaces\TimeInterface;
7
use \common\interfaces\BehaviorInterface;
8
use \common\interfaces\UserBehaviorInterface;
9
use \common\components\ActiveRecord;
10
use yii\db\Query;
11
use yii\helpers\ArrayHelper as AH;
12
use \DateTime;
13
use \DateTimeZone;
14
use yii\db\Expression;
15
16
/**
17
 * This is the model class for table "user_behavior_link".
18
 *
19
 * @property integer $id
20
 * @property integer $user_id
21
 * @property integer $behavior_id
22
 * @property string $date
23
 *
24
 * @property Behavior $user
25
 */
26
class UserBehavior extends ActiveRecord implements UserBehaviorInterface
27
{
28
  private $time;
29
  private $behavior;
30
31
  public function __construct(BehaviorInterface $behavior, TimeInterface $time, $config = []) {
32
    $this->behavior = $behavior;
33
    $this->time = $time;
34
    parent::__construct($config);
35
  }
36
37
  /**
38
   * @inheritdoc
39
   */
40
  public static function tableName()
41
  {
42
    return 'user_behavior_link';
43
  }
44
45
  /**
46
   * @inheritdoc
47
   */
48
  public function rules()
49
  {
50
    return [
51
      [['user_id', 'behavior_id', 'date'], 'required'],
52
      [['user_id', 'behavior_id'], 'integer'],
53
      //[['date'], 'string']
54
    ];
55
  }
56
57
  /**
58
   * @inheritdoc
59
   */
60
  public function attributeLabels()
61
  {
62
    return [
63
      'id'        => 'ID',
64
      'date'      => 'Date',
65
      'user_id'   => 'User ID',
66
      'behavior_id' => 'Behavior ID',
67
    ];
68
  }
69
70
  /**
71
   * @return \yii\db\ActiveQuery
72
   */
73
  public function getUser()
74
  {
75
    return $this->hasOne(\common\models\User::class, ['id' => 'user_id']);
76
  }
77
78
  public function getPastCheckinDates() {
79
    $past_checkin_dates = [];
80
    $query = new Query;
81
    $query->params = [":user_id" => Yii::$app->user->id];
82
    $query->select("date")
83
      ->from('user_behavior_link l')
84
      ->groupBy('date, user_id')
85
      ->having('user_id = :user_id');
86
    $temp_dates = $query->all();
87
    foreach($temp_dates as $temp_date) {
88
      $past_checkin_dates[] = $this->time->convertUTCToLocal($temp_date['date']);
89
    }
90
91
    return $past_checkin_dates;
92
  }
93
94
  public function getUserBehaviorsWithCategory($checkin_date) {
95
    list($start, $end) = $this->time->getUTCBookends($checkin_date);
96
97
    $query = new Query;
98
    $query->select('*')
99
      ->from('user_behavior_link')
100
      ->orderBy('behavior_id')
101
      ->where("user_id=:user_id
102
          AND date > :start_date
103
          AND date < :end_date",
104
      [
105
        ":user_id" => Yii::$app->user->id, 
106
        ":start_date" => $start, 
107
        ":end_date" => $end
108
      ]);
109
110
    $user_behaviors = self::decorateWithCategory($query->all());
111
    return AH::map($user_behaviors, 'id', function($a) { return $a['behavior']['name']; }, function($b) {return $b['behavior']['category_id']; });
112
  }
113
114
  public function getBehaviorsByDate($start, $end) {
115
      $uo = $this->find()
116
        ->select(['id', 'user_id', 'behavior_id', 'date'])
117
        ->where(
118
          "user_id=:user_id AND date > :start_date AND date <= :end_date",
119
          ["user_id" => Yii::$app->user->id, ':start_date' => $start, ":end_date" => $end]
120
        )
121
        ->orderBy('date')
122
        ->asArray()
123
        ->all();
124
125
      return self::decorate($uo, false);
126
  }
127
128
  public function getCheckinBreakdown(\DatePeriod $datetimes) {
129
    $key = "scores_of_last_month_".Yii::$app->user->id."_".$this->time->getLocalDate();
130
    $scores = Yii::$app->cache->get($key);
0 ignored issues
show
Unused Code introduced by
The assignment to $scores is dead and can be removed.
Loading history...
131
132
    /******* REMOVE THIS ********/
133
    $scores = false;
134
    /******* END REMOVE THIS *******/
135
136
    if($scores === false) {
0 ignored issues
show
introduced by
The condition $scores === false is always true.
Loading history...
137
      $scores = [];
138
      foreach($datetimes as $datetime) {
139
        $behaviors = self::decorateWithCategory($this->getBehaviorsWithCounts($datetime));
140
        $scores[$datetime->format('Y-m-d')] = $this->getBehaviorsByCategory($behaviors);
141
      }
142
143
      Yii::$app->cache->set($key, $scores, 60*60*24);
144
    }
145
146
    return $scores;
147
  }
148
149
  /**
150
   * Returns a list of the most-selected behaviors
151
   * @param integer $limit the desired number of behaviors
152
   */
153
  public function getTopBehaviors(int $limit = 5) {
154
    return self::decorateWithCategory($this->getBehaviorsWithCounts($limit));
155
  }
156
157
  /**
158
   * Returns a list of categories and the number of selected behaviors in each category
159
   * @param array $decorated_behaviors an array of behaviors ran through self::decorateWithCategory()
160
   */
161
  public function getBehaviorsByCategory(array $decorated_behaviors) {
162
    $arr = array_reduce($decorated_behaviors, function($acc, $row) {
163
      $cat_id = $row['behavior']['category']['id'];
164
      if(array_key_exists($cat_id, $acc)) {
165
        $acc[$cat_id]['count'] += $row['count'];
166
      } else {
167
        $acc[$cat_id] = [
168
          'name'      => $row['behavior']['category']['name'],
169
          'count'     => $row['count'],
170
          'color'     => \common\models\Category::$colors[$cat_id]['color'],
171
          'highlight' => \common\models\Category::$colors[$cat_id]['highlight'],
172
        ];
173
      }
174
      return $acc;
175
    }, []);
176
    ksort($arr);
177
    return $arr;
178
  }
179
180
  public static function decorate(array $uo, $with_category = false) {
181
    foreach($uo as &$o) {
182
      if($behavior = \common\models\Behavior::getBehavior('id', $o['behavior_id'])) {
183
        $o['behavior'] = $behavior;
184
        if($with_category) {
185
          $o['behavior']['category'] = \common\models\Category::getCategory('id', $o['behavior']['category_id']);
186
        }
187
      }
188
    }
189
    return $uo;
190
  }
191
192
  public static function decorateWithCategory(array $uo) {
193
    return self::decorate($uo, true);
194
  }
195
196
  public function getBehaviorsWithCounts($limit = null) {
197
    $query = new Query;
198
    $query->params = [":user_id" => Yii::$app->user->id];
199
    $query->select("user_id, behavior_id, COUNT(id) as count")
200
      ->from('user_behavior_link')
201
      ->groupBy('behavior_id, user_id')
202
      ->having('user_id = :user_id')
203
      ->orderBy('count DESC');
204
205
    if($limit instanceof \DateTime) {
206
      list($start, $end) = $this->time->getUTCBookends($limit->format('Y-m-d'));
207
      $query->params += [':start_date' => $start, ':end_date' => $end];
208
      $query->where('user_id=:user_id AND date > :start_date AND date <= :end_date');
209
    } else if(is_int($limit)) {
210
      $query->limit($limit);
211
    }
212
213
    return $query->all();
214
  }
215
}
216