/**
  * Chat entry point - rendered via Ajax or pre-rendered in JS variable
  */
 public function executeContents()
 {
     global $wgUser, $wgSitename, $wgOut, $wgExtensionsPath, $wgContLang, $wgReadOnly, $wgEnableWallExt;
     wfProfileIn(__METHOD__);
     // Since there is no chat in the backup datacenter yet, if we're in read-only, disable the entry-point.
     // Depending on the actual failure, chat may or may not work, but the user would have to get there via URL which
     // is essentially saying that they accept some risk since they're going somewhere our interface doesn't direct them to.
     // If it's just, eg: a database problem, then they may get lucky and be able to use most of the chat features (kickbanning wouldn't work, etc.).
     if (empty($wgReadOnly)) {
         // Main variables
         $this->profileType = !empty($wgEnableWallExt) ? 'message-wall' : 'talk-page';
         $this->linkToSpecialChat = SpecialPage::getTitleFor("Chat")->escapeLocalUrl();
         $this->isLoggedIn = $wgUser->isLoggedIn();
         $this->profileAvatarUrl = $this->isLoggedIn ? AvatarService::getAvatarUrl($wgUser->getName(), ChatRailController::AVATAR_SIZE) : '';
         // List of other people in chat
         $this->totalInRoom = 0;
         // Gets array of users currently in chat to populate rail module and user stats menus
         $chattersIn = NodeApiClient::getChatters($this->totalInRoom);
         $this->totalInRoom = count($chattersIn);
         $chatters = array();
         foreach ($chattersIn as $i => $val) {
             $chatters[$i] = array();
             $cacheChatter = $this->getCachedUser($val);
             if (!empty($cacheChatter)) {
                 $chatters[$i] = $cacheChatter;
                 continue;
             }
             $chatters[$i]['username'] = $val;
             $chatters[$i]['avatarUrl'] = AvatarService::getAvatarUrl($chatters[$i]['username'], ChatRailController::AVATAR_SIZE);
             // get stats for edit count and member since
             $user = User::newFromName($val);
             if (is_object($user)) {
                 $userStatsService = new UserStatsService($user->getId());
                 $stats = $userStatsService->getStats();
                 // edit count
                 $chatters[$i]['editCount'] = $wgContLang->formatNum((int) $stats['edits']);
                 // member since
                 $chatters[$i]['showSince'] = $chatters[$i]['editCount'] != 0;
                 $date = getdate(strtotime($stats['date']));
                 global $wgLang;
                 $chatters[$i]['since'] = $wgLang->getMonthAbbreviation($date['mon']) . ' ' . $date['year'];
                 // profile page
                 if ($this->profileType == 'message-wall') {
                     $chatters[$i]['profileUrl'] = Title::makeTitle(NS_USER_WALL, $chatters[$i]['username'])->getFullURL();
                 } else {
                     $chatters[$i]['profileUrl'] = Title::makeTitle(NS_USER_TALK, $chatters[$i]['username'])->getFullURL();
                 }
                 // contribs page
                 $chatters[$i]['contribsUrl'] = SpecialPage::getTitleFor('Contributions', $chatters[$i]['username'])->getFullURL();
             }
             $this->cacheUser($val, $chatters[$i]);
         }
         $this->chatters = $chatters;
     }
     // Cache the entire call in varnish (and browser).
     $this->response->setCacheValidity(self::CACHE_DURATION, self::CACHE_DURATION, array(WikiaResponse::CACHE_TARGET_BROWSER, WikiaResponse::CACHE_TARGET_VARNISH));
     wfProfileOut(__METHOD__);
 }
 /**
  * Return information about users present in the chat channel. This method has its internal cache. Method returns
  * an array, where each of the users is described by the following attributes:
  * * username - chatter login
  * * avatarUrl - chatter avatar url
  * * editCount - number of chatter's edits
  * * showSince - flag indicating if we can display the information when the chatter joined the wiki
  * * since_year && since_month - month and year, when chatter joined this wiki
  * * profileUrl - link to chatter talk page (or message wall, if it's enabled)
  * * contribsUrl - link to chatter contribution page
  * @return array array containing chatters info
  */
 public static function getChatUsersInfo()
 {
     ChatHelper::info(__METHOD__ . ': Method called');
     global $wgReadOnly;
     wfProfileIn(__METHOD__);
     $chatters = [];
     if (empty($wgReadOnly)) {
         // cache the whole response
         // individual users are cached anyway, but still we gain performance making just one memcache request instead of several
         $chatters = WikiaDataAccess::cache(self::getChatUsersMemcKey(), ChatEntryPoint::CHAT_USER_LIST_CACHE, function () {
             global $wgEnableWallExt;
             $chatters = [];
             // Gets array of users currently in chat to populate rail module and user stats menus
             $chattersIn = NodeApiClient::getChatters();
             foreach ($chattersIn as $i => $val) {
                 $chatters[$i] = WikiaDataAccess::cache(wfMemcKey('chatavatars', $val, 'v2'), 60 * 60, function () use($wgEnableWallExt, $val) {
                     $chatter = ['username' => $val, 'avatarUrl' => AvatarService::getAvatarUrl($val, ChatRailController::AVATAR_SIZE)];
                     // get stats for edit count and member since
                     $user = User::newFromName($val);
                     if ($user instanceof User) {
                         $userStatsService = new UserStatsService($user->getId());
                         $stats = $userStatsService->getStats();
                         // edit count
                         $chatter['editCount'] = $stats['edits'];
                         // member since
                         $chatter['showSince'] = $chatter['editCount'] != 0;
                         if ($chatter['showSince']) {
                             $date = getdate(strtotime($stats['date']));
                             $chatter['since_year'] = $date['year'];
                             $chatter['since_month'] = $date['mon'];
                         }
                         if (!empty($wgEnableWallExt)) {
                             $chatter['profileUrl'] = Title::makeTitle(NS_USER_WALL, $chatter['username'])->getFullURL();
                         } else {
                             $chatter['profileUrl'] = Title::makeTitle(NS_USER_TALK, $chatter['username'])->getFullURL();
                         }
                         $chatter['contribsUrl'] = SpecialPage::getTitleFor('Contributions', $chatter['username'])->getFullURL();
                     }
                     return $chatter;
                 });
             }
             return $chatters;
         });
     }
     wfProfileOut(__METHOD__);
     return $chatters;
 }