Completed
Pull Request — master (#163)
by Corey
03:24
created

UserBehavior::calculateScoreByUTCRange()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 5
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 5
c 0
b 0
f 0
rs 9.4285
cc 1
eloc 3
nc 1
nop 2
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', 'behaviorr_id', 'date'], 'required'],
52
      [['user_id', 'behaviorr_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
  /**
129
   * Returns a list of the most-selected behaviors
130
   * @param integer $limit the desired number of behaviors
131
   */
132
  public function getTopBehaviors(int $limit = 5) {
133
    return self::decorateWithCategory($this->getBehaviorsWithCounts($limit));
134
  }
135
136
  /**
137
   * Returns a list of categories and the number of selected behaviors in each category
138
   */
139
  public function getBehaviorsByCategory(\DateTime $date = null) {
140
    $behaviors = self::decorateWithCategory($this->getBehaviorsWithCounts($date));
141
142
    $arr = array_reduce($behaviors, function($acc, $row) {
143
      $cat_id = $row['behavior']['category']['id'];
144
      if(array_key_exists($cat_id, $acc)) {
145
        $acc[$cat_id]['count'] += $row['count'];
146
      } else {
147
        $acc[$cat_id] = [
148
          'name'      => $row['behavior']['category']['name'],
149
          'count'     => $row['count'],
150
          'color'     => \common\models\Category::$colors[$cat_id]['color'],
151
          'highlight' => \common\models\Category::$colors[$cat_id]['highlight'],
152
        ];
153
      }
154
      return $acc;
155
    }, []);
156
    ksort($arr);
157
    return $arr;
158
  }
159
160
  public static function decorate(Array $uo, $with_category = false) {
161
    foreach($uo as &$o) {
162
      if($behavior = \common\models\Behavior::getBehavior('id', $o['behavior_id'])) {
163
        $o['behavior'] = $behavior;
164
        if($with_category) {
165
          $o['behavior']['category'] = \common\models\Category::getCategory('id', $o['behavior']['category_id']);
166
        }
167
      }
168
    }
169
    return $uo;
170
  }
171
172
  public static function decorateWithCategory(Array $uo) {
173
    return self::decorate($uo, true);
174
  }
175
176
  public function getBehaviorsWithCounts($limit = null) {
177
    $query = new Query;
178
    $query->params = [":user_id" => Yii::$app->user->id];
179
    $query->select("user_id, behavior_id, COUNT(id) as count")
180
      ->from('user_behavior_link')
181
      ->groupBy('behavior_id, user_id')
182
      ->having('user_id = :user_id')
183
      ->orderBy('count DESC');
184
185
    if($limit instanceof \DateTime) {
186
      list($start, $end) = $this->time->getUTCBookends($limit->format('Y-m-d'));
187
      $query->params += [':start_date' => $start, ':end_date' => $end];
188
      $query->where('user_id=:user_id AND date > :start_date AND date <= :end_date');
189
    } else if(is_int($limit)) {
190
      $query->limit($limit);
191
    }
192
193
    return $query->all();
194
  }
195
}
196