public static function exportCommentsForText($projectId, $textId, $params)
 {
     $project = new ProjectModel($projectId);
     $text = new TextModel($project, $textId);
     $usxHelper = new UsxHelper($text->content);
     $textInfo = $usxHelper->getMetadata();
     $questionlist = new QuestionAnswersListModel($project, $textId);
     $questionlist->read();
     $dl = array('complete' => true, 'inprogress' => false, 'answerCount' => 0, 'commentCount' => 0, 'totalCount' => 0, 'xml' => "<CommentList>\n");
     foreach ($questionlist->entries as $question) {
         if (!array_key_exists('isArchived', $question) || !$question['isArchived']) {
             foreach ($question['answers'] as $answerId => $answer) {
                 if (!$params['exportFlagged'] || array_key_exists('isToBeExported', $answer) && $answer['isToBeExported']) {
                     // if the answer is tagged with an export tag
                     $dl['answerCount']++;
                     $dl['xml'] .= self::makeCommentXml($answer['tags'], $answer['score'], $textInfo, $answerId, $answer);
                     if ($params['exportComments']) {
                         foreach ($answer['comments'] as $commentId => $comment) {
                             $dl['xml'] .= self::makeCommentXml(array(), 0, $textInfo, $commentId, $comment);
                             $dl['commentCount']++;
                         }
                     }
                 }
             }
         }
     }
     $dl['totalCount'] = $dl['answerCount'] + $dl['commentCount'];
     $dl['xml'] .= "</CommentList>";
     $dl['filename'] = 'Comments_sf_' . date('Ymd_Gi') . '.xml';
     //$dl['filename'] = preg_replace("([^\w\d\-]|[\.]{2,})", '_', $filename) . '.xml';
     return $dl;
 }
 /**
  * @param string $projectId
  * @param string $textId
  * @param string $userId
  * @returns array - the DTO array
  */
 public static function encode($projectId, $textId, $userId)
 {
     $user = new UserModel($userId);
     $project = new SfchecksProjectModel($projectId);
     $text = new TextModel($project, $textId);
     $questionList = new QuestionAnswersListModel($project, $textId);
     $questionList->read();
     $data = array();
     $data['text'] = JsonEncoder::encode($text);
     $data['archivedQuestions'] = array();
     foreach ($questionList->entries as $questionData) {
         $question = new QuestionModel($project, $questionData['id']);
         if ($question->isArchived) {
             // Just want answer count, not whole list
             $questionData['answerCount'] = count($questionData['answers']);
             $responseCount = 0;
             // "Reponses" = answers + comments
             foreach ($questionData['answers'] as $a) {
                 $commentCount = count($a['comments']);
                 $responseCount += $commentCount + 1;
                 // +1 for this answer
             }
             $questionData['responseCount'] = $responseCount;
             unset($questionData['answers']);
             $questionData['dateModified'] = $question->dateModified->asDateTimeInterface()->format(\DateTime::RFC2822);
             $data['archivedQuestions'][] = $questionData;
         }
     }
     $data['rights'] = RightsHelper::encode($user, $project);
     $data['bcs'] = BreadCrumbHelper::encode('settings', $project, $text, null);
     return $data;
 }
 /**
  * @param string $projectId
  * @param string $textId
  * @param string $userId
  * @return array - the DTO array
  * @throws ResourceNotAvailableException
  */
 public static function encode($projectId, $textId, $userId)
 {
     $project = new SfchecksProjectModel($projectId);
     $text = new TextModel($project, $textId);
     $user = new UserModel($userId);
     if (($project->isArchived || $text->isArchived) && $project->users[$userId]->role != ProjectRoles::MANAGER) {
         throw new ResourceNotAvailableException("This Text is no longer available. If this is incorrect contact your project manager.");
     }
     $questionList = new QuestionAnswersListModel($project, $textId);
     $questionList->read();
     $data = array();
     $data['rights'] = RightsHelper::encode($user, $project);
     $data['entries'] = array();
     $data['project'] = array('id' => $projectId, 'name' => $project->projectName, 'slug' => $project->databaseName(), 'allowAudioDownload' => $project->allowAudioDownload);
     $data['text'] = JsonEncoder::encode($text);
     $usxHelper = new UsxHelper($text->content);
     $data['text']['content'] = $usxHelper->toHtml();
     foreach ($questionList->entries as $questionData) {
         $question = new QuestionModel($project, $questionData['id']);
         if (!$question->isArchived) {
             // Just want answer count, not whole list
             $questionData['answerCount'] = count($questionData['answers']);
             $responseCount = 0;
             // "Reponses" = answers + comments
             foreach ($questionData['answers'] as $a) {
                 $commentCount = count($a['comments']);
                 $responseCount += $commentCount + 1;
                 // +1 for this answer
             }
             $questionData['responseCount'] = $responseCount;
             unset($questionData['answers']);
             $questionData['dateCreated'] = $question->dateCreated->asDateTimeInterface()->format(\DateTime::RFC2822);
             $data['entries'][] = $questionData;
         }
     }
     // sort Questions with newest at the top
     usort($data['entries'], function ($a, $b) {
         $sortOn = 'dateCreated';
         if (array_key_exists($sortOn, $a) && array_key_exists($sortOn, $b)) {
             return strtotime($a[$sortOn]) < strtotime($b[$sortOn]) ? 1 : -1;
         } else {
             return 0;
         }
     });
     $data['count'] = count($data['entries']);
     return $data;
 }
 public static function UserEngagementReport($projectId)
 {
     $project = ProjectModel::getById($projectId);
     $output = str_pad('**** User Engagement Report ****', 120, " ", STR_PAD_BOTH) . "\n";
     $output .= str_pad(date(DATE_RFC2822), 120, " ", STR_PAD_BOTH) . "\n\n";
     $data = array();
     $activeUsers = array();
     $managerUsers = array();
     $inactiveUsers = array();
     $invalidUsers = array();
     $listModel = new UserListProjectModel($projectId);
     $listModel->read();
     if ($listModel->count > 0) {
         $textListModel = new TextListModel($project);
         $textListModel->read();
         $questions = array();
         foreach ($textListModel->entries as $text) {
             $questionListModel = new QuestionAnswersListModel($project, $text['id']);
             $questionListModel->read();
             $questions = array_merge($questions, array_map(function ($q) use($text) {
                 $q['textRef'] = $text['id'];
                 return $q;
             }, $questionListModel->entries));
         }
         $answerCtr = 0;
         $commentCtr = 0;
         foreach ($listModel->entries as $user) {
             $userModel = new UserModel($user['id']);
             $user['isActive'] = $userModel->active;
             $user['questions'] = 0;
             $user['texts'] = 0;
             $user['answers'] = 0;
             $user['comments'] = 0;
             $user['responses'] = 0;
             $user['textIds'] = array();
             if (!$user['isActive']) {
                 if (!$user['email']) {
                     $user['email'] = $userModel->emailPending;
                 }
                 array_push($invalidUsers, $user);
                 continue;
             }
             if ($project->users->offsetExists($user['id'])) {
                 $user['role'] = $project->users[$user['id']]->role;
             } else {
                 $user['role'] = ProjectRoles::NONE;
             }
             $answerCtr = 0;
             $commentCtr = 0;
             foreach ($questions as $question) {
                 $responses = 0;
                 foreach ($question['answers'] as $answer) {
                     if (!$answer['content']) {
                         continue;
                     }
                     $answerCtr++;
                     foreach ($answer['comments'] as $comment) {
                         if (!$comment['content']) {
                             continue;
                         }
                         $commentCtr++;
                         if ($comment['userRef'] && strval($comment['userRef']) == $user['id']) {
                             $user['comments']++;
                             $user['responses']++;
                             array_push($user['textIds'], $question['textRef']);
                             $responses++;
                         }
                     }
                     if ($answer['userRef'] && strval($answer['userRef']) == $user['id']) {
                         $user['answers']++;
                         $user['responses']++;
                         array_push($user['textIds'], $question['textRef']);
                         $responses++;
                     }
                 }
                 if ($responses > 0) {
                     $user['questions']++;
                 }
             }
             $user['texts'] = count(array_unique($user['textIds']));
             if ($user['role'] == ProjectRoles::MANAGER) {
                 array_push($managerUsers, $user);
             } elseif ($user['responses'] > 0) {
                 array_push($activeUsers, $user);
             } else {
                 array_push($inactiveUsers, $user);
             }
         }
         $output .= $project->projectName . " Project\n";
         $output .= "Texts (T's) in Project: " . $textListModel->count . "\n";
         $output .= "Questions (Q's) in Project: " . count($questions) . "\n";
         $output .= "Responses (R's) in Project (Answers + Comments): " . ($answerCtr + $commentCtr) . "\n";
         $output .= "Answers (A's) in Project: " . $answerCtr . "\n";
         $output .= "Comments (C's) in Project: " . $commentCtr . "\n";
     } else {
         $output .= "This project has no users\n\n";
     }
     $sortByResponses = function ($a, $b) {
         if ($a['responses'] > $b['responses']) {
             return -1;
         } elseif ($a['responses'] < $b['responses']) {
             return 1;
         } else {
             if ($a['answers'] > $b['answers']) {
                 return -1;
             } elseif ($a['answers'] < $b['answers']) {
                 return 1;
             } else {
                 if ($a['comments'] > $b['comments']) {
                     return -1;
                 } elseif ($a['comments'] < $b['comments']) {
                     return 1;
                 } else {
                     return strcmp($a['username'], $b['username']);
                 }
             }
         }
     };
     $sortByName = function ($a, $b) {
         return strcasecmp($a['name'], $b['name']);
     };
     usort($activeUsers, $sortByResponses);
     usort($managerUsers, $sortByResponses);
     usort($inactiveUsers, $sortByName);
     usort($invalidUsers, $sortByName);
     $output .= "\n\nManagers: " . count($managerUsers) . "\n" . str_pad("Name", 30) . str_pad("Email", 35) . str_pad("Username", 25) . str_pad("R's", 5) . str_pad("A's", 5) . str_pad("C's", 5) . str_pad("Q's", 5) . str_pad("T's", 5) . "\n\n";
     foreach ($managerUsers as $user) {
         $output .= str_pad($user['name'], 30) . str_pad($user['email'], 35) . str_pad($user['username'], 25) . str_pad($user['responses'], 5) . str_pad($user['answers'], 5) . str_pad($user['comments'], 5) . str_pad($user['questions'], 5) . str_pad($user['texts'], 5) . "\n";
     }
     $output .= "\n\nActive Users: " . count($activeUsers) . "\n" . str_pad("Name", 30) . str_pad("Email", 35) . str_pad("Username", 25) . str_pad("R's", 5) . str_pad("A's", 5) . str_pad("C's", 5) . str_pad("Q's", 5) . str_pad("T's", 5) . "\n\n";
     foreach ($activeUsers as $user) {
         $output .= str_pad($user['name'], 30) . str_pad($user['email'], 35) . str_pad($user['username'], 25) . str_pad($user['responses'], 5) . str_pad($user['answers'], 5) . str_pad($user['comments'], 5) . str_pad($user['questions'], 5) . str_pad($user['texts'], 5) . "\n";
     }
     $output .= "\n\nInactive Users (never engaged): " . count($inactiveUsers) . "\n" . str_pad("Name", 30) . str_pad("Email", 35) . str_pad("Username", 25) . "\n\n";
     foreach ($inactiveUsers as $user) {
         $output .= str_pad($user['name'], 30) . str_pad($user['email'], 35) . str_pad($user['username'], 25) . "\n";
     }
     $output .= "\n\nInvited Users (but never validated or logged in): " . count($invalidUsers) . "\n" . str_pad("Name", 30) . str_pad("Email", 35) . str_pad("Username", 25) . "\n\n";
     foreach ($invalidUsers as $user) {
         $output .= str_pad($user['name'], 30) . str_pad($user['email'], 35) . str_pad($user['username'], 25) . "\n";
     }
     $data['output'] = $output;
     $data['result'] = array('managerUsers' => $managerUsers, 'activeUsers' => $activeUsers, 'inactiveUsers' => $inactiveUsers, 'invitedUsers' => $invalidUsers);
     return $data;
 }
 public function listQuestionsWithAnswers()
 {
     $questionList = new QuestionAnswersListModel($this->_projectModel, $this->id->asString());
     $questionList->read();
     return $questionList;
 }