CheckinForm::rules()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 14
Code Lines 9

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 9
c 1
b 0
f 0
dl 0
loc 14
rs 9.9666
cc 1
nc 1
nop 0
1
<?php
2
namespace site\models;
3
4
use Yii;
5
use yii\base\Model;
6
use yii\db\Expression;
7
use yii\helpers\ArrayHelper as AH;
8
use common\interfaces\BehaviorInterface;
9
10
/**
11
 * Checkin form
12
 */
13
class CheckinForm extends Model
14
{
15
  public $behaviors1;
16
  public $behaviors2;
17
  public $behaviors3;
18
  public $behaviors4;
19
  public $behaviors5;
20
  public $behaviors6;
21
  public $behaviors7;
22
  public $custom_behaviors = [];
23
24
  public $compiled_behaviors = [];
25
26
  /**
27
   * @inheritdoc
28
   */
29
  public function rules()
30
  {
31
    return [
32
      [
33
        [
34
          'behaviors1',
35
          'behaviors2',
36
          'behaviors3',
37
          'behaviors4',
38
          'behaviors5',
39
          'behaviors6',
40
          'behaviors7'
41
        ],
42
        'validateBehaviors'],
43
    ];
44
  }
45
46
  public function attributeLabels() {
47
    return [
48
      'behaviors1' => 'Restoration',
49
      'behaviors2' => 'Forgetting Priorities',
50
      'behaviors3' => 'Anxiety',
51
      'behaviors4' => 'Speeding Up',
52
      'behaviors5' => 'Ticked Off',
53
      'behaviors6' => 'Exhausted',
54
      'behaviors7' => 'Relapsed/Moral Failure'
55
    ];
56
  }
57
58
  public function setBehaviors($behaviors) {
59
    foreach($behaviors as $category_id => $bhvr_set) {
60
      $attribute = "behaviors$category_id";
61
			$this->$attribute = [];
62
      foreach($bhvr_set as $behavior) {
63
        $this->{$attribute}[] = $behavior['id'];
64
      }
65
    }   
66
  }
67
68
  public function validateBehaviors($attribute, $params) {
0 ignored issues
show
Unused Code introduced by
The parameter $params is not used and could be removed. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unused  annotation

68
  public function validateBehaviors($attribute, /** @scrutinizer ignore-unused */ $params) {

This check looks for parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
69
    if (!$this->hasErrors()) {
70
      foreach($this->$attribute as $behavior) {
71
        if(!is_numeric($behavior) && !preg_match('/[0-9]{1,2}-custom/', $behavior)) {
72
          $this->addError($attribute, 'One of your behaviors is not an integer!');
73
        }
74
      }
75
    }
76
  }
77
78
  /*
79
   * compileBehaviors()
80
   *
81
   * Takes every behavior in all of the local behaviors[1-7] variables,
82
   * which can include custom behaviors as well as regular behaviors, and
83
   * splits them out into two local array variables.
84
   *
85
   * It returns true or false depending on whether or not there are any behaviors.
86
   *
87
   * @return boolean whether or not there were behaviors to compile
88
   *
89
   */
90
  public function compileBehaviors() {
91
    $behaviors = array_merge((array)$this->behaviors1,
92
                             (array)$this->behaviors2,
93
                             (array)$this->behaviors3,
94
                             (array)$this->behaviors4,
95
                             (array)$this->behaviors5,
96
                             (array)$this->behaviors6,
97
                             (array)$this->behaviors7);
98
99
    $clean_behaviors = array_filter($behaviors); // strip out false values
100
101
    // if there are no selected behaviors just return false now
102
    if(sizeof($clean_behaviors) === 0) return false;
103
104
    $self = $this;
105
    array_walk($clean_behaviors, function($bhvr) use (&$self) {
106
      if(preg_match('/.*-custom/', $bhvr)) {
107
        $self->custom_behaviors[] = $bhvr;
108
      } else {
109
        $self->compiled_behaviors[] = $bhvr;
110
      }
111
    });
112
113
    return true;
114
  }
115
116
  public function deleteToday() {
117
    $time = Yii::$container->get(\common\interfaces\TimeInterface::class);
118
    $user_behavior = Yii::$container->get(\common\interfaces\UserBehaviorInterface::class);
119
120
    $date = $time->getLocalDate();
121
    list($start, $end) = $time->getUTCBookends($date);
122
123
    $user_behavior->deleteAll("user_id=:user_id 
124
      AND date > :start_date 
125
      AND date < :end_date", 
126
      [
127
        "user_id" => Yii::$app->user->id, 
128
        ':start_date' => $start, 
129
        ":end_date" => $end
130
      ]
131
    );
132
133
    // delete cached behaviors
134
    array_map(function($period) use ($time) {
135
      $key = "checkins_".Yii::$app->user->id."_{$period}_".$time->getLocalDate();
136
      Yii::$app->cache->delete($key);
137
    }, [30, 90, 180]);
138
  }
139
140
  /**
141
   * Takes an array of the default behaivors and given behaviors from the user and returns them merged together.
142
   * This is used for the generation of the CheckinForm behavior list.
143
   * @param array $user_behaviors an array of UserBehaviors indexed by the category. Typically just the result of self::$getByDate().
144
   * @return array the two supplied arrays merged together
145
   */
146
  public function mergeWithDefault(array $user_behaviors) {
147
    $behaviors = AH::index(Yii::$container->get(BehaviorInterface::class)::$behaviors, 'name', "category_id");
148
    array_walk($behaviors, function(&$bhvrs, $cat_id) use ($user_behaviors) {
149
      if(array_key_exists($cat_id, $user_behaviors)) {
150
        $bhvrs = AH::merge($bhvrs, $user_behaviors[$cat_id]);
151
      }
152
    });
153
    return $behaviors;
154
  }
155
156
  /*
157
   * getCustomBehaviors()
158
   *
159
   * takes the array of strings ($this->custom_behaviors) that
160
   * looks like ['3-custom', '7-custom'] and converts it to an
161
   * integer array like [3, 7].
162
   *
163
   * @return Array of integers, ids of selected custom behaviors
164
   */
165
  public function getCustomBehaviors() {
166
    return array_map(function($cs) {
167
      return (int)explode('-', $cs)[0];
168
    }, $this->custom_behaviors);
169
  }
170
171
  public function save() {
172
    if(empty($this->compiled_behaviors) && empty($this->custom_behaviors)) {
173
      // maybe we haven't compiled the behaviors yet
174
      $exit = !!!$this->compileBehaviors();
175
      if($exit) return false;
176
    }
177
178
    $custom_bhvrs = \common\models\CustomBehavior::find()
179
      ->where([
180
      'user_id' => Yii::$app->user->id,
181
      'id' => (array)$this->getCustomBehaviors()
182
    ])
183
    ->asArray()
184
    ->all();
185
186
    $user_behavior = Yii::$container->get(\common\interfaces\UserBehaviorInterface::class);
187
188
    $rows = [];
189
    // this can be condensed....but we are optimizing for readability
190
    foreach($this->compiled_behaviors as $behavior_id) {
191
      $behavior_id = (int)$behavior_id;
192
      $behavior = \common\models\Behavior::getBehavior('id', $behavior_id);
193
      $category_id = $behavior['category_id'];
194
      $temp = [
195
        Yii::$app->user->id,
196
        (int)$behavior_id,
197
        (int)$category_id,
198
        null,
199
        new Expression("now()::timestamp")
200
      ];
201
      $rows[] = $temp;
202
    }
203
204
    foreach($custom_bhvrs as $cb) {
205
      $temp = [
206
        Yii::$app->user->id,
207
        null,
208
        (int)$cb['category_id'],
209
        $cb['name'],
210
        new Expression("now()::timestamp")
211
      ];
212
      $rows[] = $temp;
213
    }
214
215
    // this batchInsert() method properly escapes the inputted data
216
    Yii::$app
217
      ->db
218
      ->createCommand()
219
      ->batchInsert(
220
        $user_behavior->tableName(),
221
        ['user_id', 'behavior_id', 'category_id', 'custom_behavior', 'date'],
222
        $rows
223
      )->execute();
224
225
    // if the user has publicised their check-in graph, create the image
226
    if(Yii::$app->user->identity->expose_graph) {
0 ignored issues
show
Bug introduced by
Accessing expose_graph on the interface yii\web\IdentityInterface suggest that you code against a concrete implementation. How about adding an instanceof check?
Loading history...
227
      $checkins_last_month = $user_behavior->getCheckInBreakdown();
228
229
      if($checkins_last_month) {
230
        Yii::$container
231
          ->get(\common\components\Graph::class, [Yii::$app->user->identity])
232
          ->create($checkins_last_month, true);
233
      }
234
    }
235
  }
236
}
237