| Total Complexity | 76 | 
| Total Lines | 623 | 
| Duplicated Lines | 0 % | 
| Changes | 0 | ||
Complex classes like User often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use User, and based on these observations, apply Extract Interface, too.
| 1 | <?php | ||
| 37 | class User extends ActiveRecord implements IdentityInterface, UserInterface | ||
| 38 | { | ||
| 39 | const STATUS_DELETED = 0; | ||
| 40 | const STATUS_ACTIVE = 10; | ||
| 41 | |||
| 42 | const ROLE_USER = 10; | ||
| 43 | |||
| 44 | const CONFIRMED_STRING = '_confirmed'; | ||
| 45 | |||
| 46 | public $user_behavior; | ||
| 47 | public $question; | ||
| 48 | public $time; | ||
| 49 | |||
| 50 |   public function __construct(UserBehaviorInterface $user_behavior, QuestionInterface $question, TimeInterface $time, $config = []) { | ||
| 51 | $this->user_behavior = $user_behavior; | ||
| 52 | $this->question = $question; | ||
| 53 | $this->time = $time; | ||
| 54 | parent::__construct($config); | ||
| 55 | } | ||
| 56 | |||
| 57 |   public function afterFind() { | ||
| 58 | $this->time = new \common\components\Time($this->timezone); | ||
| 59 | parent::afterFind(); | ||
| 60 | } | ||
| 61 | |||
| 62 |   public function afterRefresh() { | ||
| 63 | $this->time = new \common\components\Time($this->timezone); | ||
| 64 | parent::afterRefresh(); | ||
| 65 | } | ||
| 66 | |||
| 67 |   //public function afterSave() { | ||
| 68 | // $this->time = new \common\components\Time($this->timezone); | ||
| 69 | // parent::afterSave(); | ||
| 70 | //} | ||
| 71 | |||
| 72 | /** | ||
| 73 | * @inheritdoc | ||
| 74 | */ | ||
| 75 | |||
| 76 | public function behaviors() | ||
| 77 |   { | ||
| 78 | return [ | ||
| 79 | 'timestamp' => [ | ||
| 80 | 'class' => 'yii\behaviors\TimestampBehavior', | ||
| 81 | 'attributes' => [ | ||
| 82 | ActiveRecord::EVENT_BEFORE_INSERT => ['created_at', 'updated_at'], | ||
| 83 | ActiveRecord::EVENT_BEFORE_UPDATE => ['updated_at'], | ||
| 84 | ], | ||
| 85 | ], | ||
| 86 | ]; | ||
| 87 | } | ||
| 88 | |||
| 89 | /** | ||
| 90 | * @inheritdoc | ||
| 91 | */ | ||
| 92 | public function rules() | ||
| 93 |   { | ||
| 94 | return [ | ||
| 95 | ['status', 'default', 'value' => self::STATUS_ACTIVE], | ||
| 96 | ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]], | ||
| 97 | |||
| 98 | ['role', 'default', 'value' => self::ROLE_USER], | ||
| 99 | ['role', 'in', 'range' => [self::ROLE_USER]], | ||
| 100 | ]; | ||
| 101 | } | ||
| 102 | |||
| 103 |   public function getPartnerEmails() { | ||
| 104 | return [ | ||
| 105 | $this->partner_email1, | ||
| 106 | $this->partner_email2, | ||
| 107 | $this->partner_email3, | ||
| 108 | ]; | ||
| 109 | } | ||
| 110 | |||
| 111 | /** | ||
| 112 | * @inheritdoc | ||
| 113 | */ | ||
| 114 | public static function findIdentity($id) | ||
| 115 |   { | ||
| 116 | return static::findOne($id); | ||
|  | |||
| 117 | } | ||
| 118 | |||
| 119 | /** | ||
| 120 | * @inheritdoc | ||
| 121 | */ | ||
| 122 | public static function findIdentityByAccessToken($token, $type = null) | ||
| 123 |   { | ||
| 124 |     throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); | ||
| 125 | } | ||
| 126 | |||
| 127 | /** | ||
| 128 | * Finds user by email | ||
| 129 | * | ||
| 130 | * @param string $email | ||
| 131 | * @return static|null | ||
| 132 | */ | ||
| 133 | public function findByEmail($email) | ||
| 134 |   { | ||
| 135 | return $this->findOne(['email' => $email, 'status' => self::STATUS_ACTIVE]); | ||
| 136 | } | ||
| 137 | |||
| 138 | /** | ||
| 139 | * Finds user by password reset token | ||
| 140 | * | ||
| 141 | * @param string $token password reset token | ||
| 142 | * @return static|null | ||
| 143 | */ | ||
| 144 | public function findByPasswordResetToken($token) | ||
| 145 |   { | ||
| 146 |     if(!$this->isTokenCurrent($token)) { | ||
| 147 | return null; | ||
| 148 | } | ||
| 149 | |||
| 150 | return $this->findOne([ | ||
| 151 | 'password_reset_token' => $token, | ||
| 152 | 'status' => self::STATUS_ACTIVE, | ||
| 153 | ]); | ||
| 154 | } | ||
| 155 | |||
| 156 | /** | ||
| 157 | * Finds user by email verification token | ||
| 158 | * | ||
| 159 | * @param string $token email verification token | ||
| 160 | * @return static|null | ||
| 161 | */ | ||
| 162 | public function findByVerifyEmailToken($token) | ||
| 163 |   { | ||
| 164 | if($this->isTokenConfirmed($token)) return null; | ||
| 165 | |||
| 166 | $user = $this->findOne([ | ||
| 167 | 'verify_email_token' => [$token, $token . self::CONFIRMED_STRING], | ||
| 168 | 'status' => self::STATUS_ACTIVE, | ||
| 169 | ]); | ||
| 170 | |||
| 171 |     if($user) { | ||
| 172 | if(!$this->isTokenConfirmed($token) && | ||
| 173 |          !$this->isTokenCurrent($token, 'user.verifyAccountTokenExpire')) { | ||
| 174 | return null; | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | return $user; | ||
| 179 | } | ||
| 180 | |||
| 181 | /** | ||
| 182 | * Finds user by email change token | ||
| 183 | * | ||
| 184 | * @param string $token email change token | ||
| 185 | * @return static|null | ||
| 186 | */ | ||
| 187 | public function findByChangeEmailToken($token) | ||
| 188 |   { | ||
| 189 | $user = static::findOne([ | ||
| 190 | 'change_email_token' => $token, | ||
| 191 | 'status' => self::STATUS_ACTIVE, | ||
| 192 | ]); | ||
| 193 | |||
| 194 |     if($user) { | ||
| 195 |       if(!$user->isTokenCurrent($token, 'user.verifyAccountTokenExpire')) { | ||
| 196 | return null; | ||
| 197 | } | ||
| 198 | } | ||
| 199 | |||
| 200 | return $user; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * Finds out if a token is current or expired | ||
| 205 | * | ||
| 206 | * @param string $token verification token | ||
| 207 | * @param string $paramPath Yii app param path | ||
| 208 | * @return boolean | ||
| 209 | */ | ||
| 210 |   public function isTokenCurrent($token, String $paramPath = 'user.passwordResetTokenExpire') { | ||
| 219 | } | ||
| 220 | |||
| 221 | /* | ||
| 222 | * Checks if $token ends with the $match string | ||
| 223 | * | ||
| 224 | * @param string $token verification token (the haystack) | ||
| 225 | * @param string $match the needle to search for | ||
| 226 | */ | ||
| 227 |   public function isTokenConfirmed($token = null, String $match = self::CONFIRMED_STRING) { | ||
| 228 | if(is_null($token)) $token = $this->verify_email_token; | ||
| 229 | return substr($token, -strlen($match)) === $match; | ||
| 230 | } | ||
| 231 | |||
| 232 | /** | ||
| 233 | * @inheritdoc | ||
| 234 | */ | ||
| 235 | public function getId() | ||
| 236 |   { | ||
| 237 | return $this->getPrimaryKey(); | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * @inheritdoc | ||
| 242 | */ | ||
| 243 | public function getAuthKey() | ||
| 244 |   { | ||
| 245 | return $this->auth_key; | ||
| 246 | } | ||
| 247 | |||
| 248 |   public function getTimezone() { | ||
| 249 | return $this->timezone; | ||
| 250 | } | ||
| 251 | |||
| 252 |   public function isVerified() { | ||
| 253 |     if(is_null($this->verify_email_token)) { | ||
| 254 | // for old users who verified their accounts before the addition of | ||
| 255 | // '_confirmed' to the token | ||
| 256 | return true; | ||
| 257 |     } else { | ||
| 258 | return !!$this->verify_email_token && $this->isTokenConfirmed($this->verify_email_token); | ||
| 259 | } | ||
| 260 | } | ||
| 261 | |||
| 262 | /** | ||
| 263 | * @inheritdoc | ||
| 264 | */ | ||
| 265 | public function validateAuthKey($authKey) | ||
| 266 |   { | ||
| 267 | return $this->getAuthKey() === $authKey; | ||
| 268 | } | ||
| 269 | |||
| 270 | /** | ||
| 271 | * Validates password | ||
| 272 | * | ||
| 273 | * @param string $password password to validate | ||
| 274 | * @return boolean if password provided is valid for current user | ||
| 275 | */ | ||
| 276 | public function validatePassword($password) | ||
| 277 |   { | ||
| 278 | return Yii::$app | ||
| 279 | ->getSecurity() | ||
| 280 | ->validatePassword($password, $this->password_hash); | ||
| 281 | } | ||
| 282 | |||
| 283 | /** | ||
| 284 | * Generates password hash from password and sets it to the model | ||
| 285 | * | ||
| 286 | * @param string $password | ||
| 287 | */ | ||
| 288 | public function setPassword($password) | ||
| 289 |   { | ||
| 290 | $this->password_hash = Yii::$app | ||
| 291 | ->getSecurity() | ||
| 292 | ->generatePasswordHash($password); | ||
| 293 | } | ||
| 294 | |||
| 295 | /** | ||
| 296 | * Generates email verification token | ||
| 297 | */ | ||
| 298 | public function generateVerifyEmailToken() | ||
| 299 |   { | ||
| 300 | $this->verify_email_token = $this->getRandomVerifyString(); | ||
| 301 | } | ||
| 302 | |||
| 303 | |||
| 304 | public function confirmVerifyEmailToken() | ||
| 305 |   { | ||
| 306 | $this->verify_email_token .= self::CONFIRMED_STRING; | ||
| 307 | } | ||
| 308 | |||
| 309 | /** | ||
| 310 | * Removes email verification token | ||
| 311 | */ | ||
| 312 | public function removeVerifyEmailToken() | ||
| 313 |   { | ||
| 314 | $this->verify_email_token = null; | ||
| 315 | } | ||
| 316 | |||
| 317 | /** | ||
| 318 | * Generates email change tokens | ||
| 319 | */ | ||
| 320 |   public function generateChangeEmailToken() { | ||
| 322 | } | ||
| 323 | |||
| 324 | /** | ||
| 325 | * Removes change email token | ||
| 326 | */ | ||
| 327 | public function removeChangeEmailToken() | ||
| 328 |   { | ||
| 329 | $this->change_email_token = null; | ||
| 330 | } | ||
| 331 | |||
| 332 | /** | ||
| 333 | * Generates "remember me" authentication key | ||
| 334 | */ | ||
| 335 | public function generateAuthKey() | ||
| 336 |   { | ||
| 337 | $this->auth_key = Yii::$app | ||
| 338 | ->getSecurity() | ||
| 339 | ->generateRandomString(); | ||
| 340 | } | ||
| 341 | |||
| 342 | /** | ||
| 343 | * Generates new password reset token | ||
| 344 | */ | ||
| 345 | public function generatePasswordResetToken() | ||
| 346 |   { | ||
| 347 | $this->password_reset_token = $this->getRandomVerifyString(); | ||
| 348 | } | ||
| 349 | |||
| 350 | /** | ||
| 351 | * Removes password reset token | ||
| 352 | */ | ||
| 353 | public function removePasswordResetToken() | ||
| 354 |   { | ||
| 355 | $this->password_reset_token = null; | ||
| 356 | } | ||
| 357 | |||
| 358 |   public function sendEmailReport($date) { | ||
| 359 | if(!$this->isPartnerEnabled()) return false; // no partner emails set | ||
| 360 | |||
| 361 | list($start, $end) = $this->time->getUTCBookends($date); | ||
| 362 | |||
| 363 | $scores_of_month = $this->user_behavior->calculateScoresOfLastMonth(); | ||
| 364 | $graph = Yii::$container | ||
| 365 | ->get(\common\components\Graph::class) | ||
| 366 | ->create($scores_of_month); | ||
| 367 | |||
| 368 | $score = $this->user_behavior->calculateScoreByUTCRange($start, $end); | ||
| 369 | $user_behaviors = $this->getUserBehaviors($date); | ||
| 370 | $user_questions = $this->getUserQuestions($date); | ||
| 371 | |||
| 372 | $messages = []; | ||
| 373 |     foreach($this->getPartnerEmails() as $email) { | ||
| 374 |       if($email) { | ||
| 375 |         $messages[] = Yii::$app->mailer->compose('checkinReport', [ | ||
| 376 | 'user' => $this, | ||
| 377 | 'email' => $email, | ||
| 378 | 'date' => $date, | ||
| 379 | 'user_behaviors' => $user_behaviors, | ||
| 380 | 'questions' => $user_questions, | ||
| 381 | 'chart_content' => $graph, | ||
| 382 | 'categories' => \common\models\Category::$categories, | ||
| 383 | 'score' => $score, | ||
| 384 | 'behaviors_list' => \common\models\Behavior::$behaviors, | ||
| 385 | ])->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name]) | ||
| 386 | ->setReplyTo($this->email) | ||
| 387 | ->setSubject($this->email." has scored high in The Faster Scale App") | ||
| 388 | ->setTo($email); | ||
| 389 | } | ||
| 390 | } | ||
| 391 | |||
| 392 | return Yii::$app->mailer->sendMultiple($messages); | ||
| 393 | } | ||
| 394 | |||
| 395 |   public function getExportData() { | ||
| 396 | $query = (new Query) | ||
| 397 | ->select( | ||
| 398 | 'l.id, | ||
| 399 | l.date AS "date", | ||
| 400 | l.behavior_id AS "behavior_id", | ||
| 401 | (SELECT q1.answer | ||
| 402 | FROM question q1 | ||
| 403 | WHERE q1.question = 1 | ||
| 404 | AND q1.user_behavior_id = l.id) AS "question1", | ||
| 405 | (SELECT q1.answer | ||
| 406 | FROM question q1 | ||
| 407 | WHERE q1.question = 2 | ||
| 408 | AND q1.user_behavior_id = l.id) AS "question2", | ||
| 409 | (SELECT q1.answer | ||
| 410 | FROM question q1 | ||
| 411 | WHERE q1.question = 3 | ||
| 412 | AND q1.user_behavior_id = l.id) AS "question3"') | ||
| 413 |       ->from('user_behavior_link l') | ||
| 414 |       ->join("LEFT JOIN", "question q", "l.id = q.user_behavior_id") | ||
| 415 |       ->where('l.user_id=:user_id', ["user_id" => Yii::$app->user->id]) | ||
| 416 |       ->groupBy('l.id, | ||
| 417 | l.date, | ||
| 418 | "question1", | ||
| 419 | "question2", | ||
| 420 | "question3"') | ||
| 421 |       ->orderBy('l.date DESC'); | ||
| 422 | |||
| 423 | return $query | ||
| 424 | ->createCommand() | ||
| 425 | ->query(); | ||
| 426 | |||
| 427 | /* Plaintext Query | ||
| 428 | SELECT l.id, | ||
| 429 | l.date AS "date", | ||
| 430 | l.behavior_id AS "behavior_id", | ||
| 431 | (SELECT q1.answer | ||
| 432 | FROM question q1 | ||
| 433 | WHERE q1.question = 1 | ||
| 434 | AND q1.user_behavior_id = l.id) AS "question1", | ||
| 435 | (SELECT q1.answer | ||
| 436 | FROM question q1 | ||
| 437 | WHERE q1.question = 2 | ||
| 438 | AND q1.user_behavior_id = l.id) AS "question2", | ||
| 439 | (SELECT q1.answer | ||
| 440 | FROM question q1 | ||
| 441 | WHERE q1.question = 3 | ||
| 442 | AND q1.user_behavior_id = l.id) AS "question3" | ||
| 443 | FROM user_behavior_link l | ||
| 444 | LEFT JOIN question q | ||
| 445 | ON l.id = q.user_behavior_id | ||
| 446 | WHERE l.user_id = 1 | ||
| 447 | GROUP BY l.id, | ||
| 448 | l.date, | ||
| 449 | "question1", | ||
| 450 | "question2", | ||
| 451 | "question3", | ||
| 452 | ORDER BY l.date DESC; | ||
| 453 | */ | ||
| 454 | } | ||
| 455 | |||
| 456 |   public function sendSignupNotificationEmail() { | ||
| 457 |     return \Yii::$app->mailer->compose('signupNotification') | ||
| 458 | ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name]) | ||
| 459 | ->setTo(\Yii::$app->params['adminEmail']) | ||
| 460 |       ->setSubject('A new user has signed up for '.\Yii::$app->name) | ||
| 461 | ->send(); | ||
| 462 | } | ||
| 463 | |||
| 464 |   public function sendVerifyEmail() { | ||
| 465 |     return \Yii::$app->mailer->compose('verifyEmail', ['user' => $this]) | ||
| 466 | ->setFrom([\Yii::$app->params['supportEmail'] => \Yii::$app->name]) | ||
| 467 | ->setTo($this->email) | ||
| 468 |       ->setSubject('Please verify your '.\Yii::$app->name .' account') | ||
| 469 | ->send(); | ||
| 470 | } | ||
| 471 | |||
| 472 |   public function sendDeleteNotificationEmail() { | ||
| 473 | if($this->isPartnerEnabled()) return false; // no partner emails set | ||
| 474 | |||
| 475 | $messages = []; | ||
| 476 |     foreach(array_merge([$this->email], $this->getPartnerEmails()) as $email) { | ||
| 477 |       if($email) { | ||
| 478 |         $messages[] = Yii::$app->mailer->compose('partnerDeleteNotification', [ | ||
| 479 | 'user' => $this, | ||
| 480 | 'email' => $email | ||
| 481 | ])->setFrom([Yii::$app->params['supportEmail'] => Yii::$app->name]) | ||
| 482 | ->setReplyTo($this->email) | ||
| 483 | ->setSubject($this->email." has deleted their The Faster Scale App account") | ||
| 484 | ->setTo($email); | ||
| 485 | } | ||
| 486 | } | ||
| 487 | |||
| 488 | return Yii::$app->mailer->sendMultiple($messages); | ||
| 489 | } | ||
| 490 | |||
| 491 |   public function getUserQuestions($local_date = null) { | ||
| 492 | if(is_null($local_date)) $local_date = $this->time->getLocalDate(); | ||
| 493 | $questions = $this->getQuestionData($local_date); | ||
| 494 | return $this->parseQuestionData($questions); | ||
| 495 | } | ||
| 496 | |||
| 497 |   public function getUserBehaviors($local_date = null) { | ||
| 498 | if(is_null($local_date)) $local_date = $this->time->getLocalDate(); | ||
| 499 | |||
| 500 | $behaviors = $this->getBehaviorData($local_date); | ||
| 501 | $behaviors = $this->user_behavior::decorateWithCategory($behaviors); | ||
| 502 | return $this->parseBehaviorData($behaviors); | ||
| 503 | } | ||
| 504 | |||
| 505 |   public function parseQuestionData($questions) { | ||
| 506 | if(!$questions) return []; | ||
| 507 | |||
| 508 | $question_answers = []; | ||
| 509 |     foreach($questions as $question) { | ||
| 510 | $behavior = $question['behavior']; | ||
| 511 | |||
| 512 | $question_answers[$behavior['id']]['question'] = [ | ||
| 513 | "id" => $behavior['id'], | ||
| 514 | "title" => $behavior['name'] | ||
| 515 | ]; | ||
| 516 | |||
| 517 | $question_answers[$behavior['id']]["answers"][] = [ | ||
| 518 | "title" => $this->question::$QUESTIONS[$question['question']], | ||
| 519 | "answer" => $question['answer'] | ||
| 520 | ]; | ||
| 521 | } | ||
| 522 | |||
| 523 | return $question_answers; | ||
| 524 | } | ||
| 525 | |||
| 526 |   public function parseBehaviorData($behaviors) { | ||
| 527 | if(!$behaviors) return []; | ||
| 528 | |||
| 529 | $opts_by_cat = []; | ||
| 530 |     foreach($behaviors as $behavior) { | ||
| 531 | $indx = $behavior['behavior']['category_id']; | ||
| 532 | |||
| 533 | $opts_by_cat[$indx]['category_name'] = $behavior['behavior']['category']['name']; | ||
| 534 | $opts_by_cat[$indx]['behaviors'][] = [ | ||
| 535 | "id" => $behavior['behavior_id'], | ||
| 536 | "name"=>$behavior['behavior']['name']]; | ||
| 537 | } | ||
| 538 | |||
| 539 | return $opts_by_cat; | ||
| 540 | } | ||
| 541 | |||
| 542 |   public function getQuestionData($local_date) { | ||
| 543 | list($start, $end) = $this->time->getUTCBookends($local_date); | ||
| 544 | |||
| 545 | $questions = $this->question->find() | ||
| 546 |       ->where("user_id=:user_id  | ||
| 547 | AND date > :start_date | ||
| 548 | AND date < :end_date", | ||
| 549 | [ | ||
| 550 | "user_id" => Yii::$app->user->id, | ||
| 551 | ':start_date' => $start, | ||
| 552 | ":end_date" => $end | ||
| 553 | ]) | ||
| 554 | ->asArray() | ||
| 555 | ->all(); | ||
| 556 | |||
| 557 | $questions = $this->user_behavior::decorate($questions); | ||
| 558 | |||
| 559 | return $questions; | ||
| 560 | } | ||
| 561 | |||
| 562 |   public function getBehaviorData($local_date) { | ||
| 563 | list($start, $end) = $this->time->getUTCBookends($local_date); | ||
| 564 | |||
| 565 | return $this->user_behavior->find() | ||
| 566 |       ->where("user_id=:user_id  | ||
| 567 | AND date > :start_date | ||
| 568 | AND date < :end_date", | ||
| 569 | [ | ||
| 570 | "user_id" => Yii::$app->user->id, | ||
| 571 | ':start_date' => $start, | ||
| 572 | ":end_date" => $end | ||
| 573 | ]) | ||
| 574 | ->asArray() | ||
| 575 | ->all(); | ||
| 576 | } | ||
| 577 | |||
| 578 |   public function isPartnerEnabled() { | ||
| 579 | if((is_integer($this->email_threshold) | ||
| 580 | && $this->email_threshold >= 0) | ||
| 581 | && ($this->partner_email1 | ||
| 582 | || $this->partner_email2 | ||
| 583 |            || $this->partner_email3)) { | ||
| 584 | return true; | ||
| 585 | } | ||
| 586 | return false; | ||
| 587 | } | ||
| 588 | |||
| 589 |   public function isOverThreshold($score) { | ||
| 590 | if(!$this->isPartnerEnabled()) return false; | ||
| 591 | |||
| 592 | $threshold = $this->email_threshold; | ||
| 593 | |||
| 594 | return (!is_null($threshold) && $score > $threshold) | ||
| 595 | ? true | ||
| 596 | : false; | ||
| 597 | } | ||
| 598 | |||
| 599 |   public function cleanExportData($data) { | ||
| 600 | $order = array_flip(["date", "behavior", "category", "question1", "question2", "question3"]); | ||
| 601 | |||
| 602 | $ret = array_map( | ||
| 603 |      function($row) use ($order) { | ||
| 604 | // change timestamp to local time (for the user) | ||
| 605 | $row['date'] = $this->time->convertUTCToLocal($row['date'], false); | ||
| 606 | |||
| 607 | // clean up things we don't need | ||
| 608 | $row['category'] = $row['behavior']['category']['name']; | ||
| 609 | $row['behavior'] = $row['behavior']['name']; | ||
| 610 | unset($row['id']); | ||
| 611 | unset($row['behavior_id']); | ||
| 612 | |||
| 613 | // sort the array into a sensible order | ||
| 614 |        uksort($row, function($a, $b) use ($order) { | ||
| 615 | return $order[$a] <=> $order[$b]; | ||
| 616 | }); | ||
| 617 | return $row; | ||
| 618 | }, | ||
| 619 | $data | ||
| 620 | ); | ||
| 621 | return $ret; | ||
| 622 | } | ||
| 623 | |||
| 624 | /* | ||
| 625 | * getIdHash() | ||
| 626 | * | ||
| 627 | * @return String a user-identifying hash | ||
| 628 | * | ||
| 629 | * After generating the hash, we run it through a url-safe base64 encoding to | ||
| 630 | * shorten it. This generated string is currently used as an identifier in | ||
| 631 | * URLs, so the shorter the better. the url-safe version has been ripped from | ||
| 632 | * https://secure.php.net/manual/en/function.base64-encode.php#103849 | ||
| 633 | * | ||
| 634 | * It does NOT take into account the user's email address. The email address | ||
| 635 | * is changeable by the user. If that was used for this function, the | ||
| 636 | * returned hash would change when the user updates their email. That would | ||
| 637 | * obviously not be desirable. | ||
| 638 | */ | ||
| 639 |   public function getIdHash() { | ||
| 640 | return rtrim( | ||
| 641 | strtr( | ||
| 642 | base64_encode( | ||
| 643 |           hash('sha256', $this->id."::".$this->created_at, true) | ||
| 644 | ), | ||
| 645 | '+/', '-_'), | ||
| 646 | '='); | ||
| 647 | } | ||
| 648 | |||
| 649 | /* | ||
| 650 | * getRandomVerifyString() | ||
| 651 | * | ||
| 652 | * @return String a randomly generated string with a timestamp appended | ||
| 653 | * | ||
| 654 | * This is generally used for verification purposes: verifying an email, password change, or email address change. | ||
| 655 | */ | ||
| 656 |   private function getRandomVerifyString() { | ||
| 660 | } | ||
| 661 | } | ||
| 662 |