/** * Adds breadcrumb entries for all the parents of the passed node id. * This is inclusive of the passed node id, but excludes "home". * Modifies $this->breadcrumbs * * @param int Node ID * @param bool If true, only add the top-most parent after home, and ignore the rest. */ protected function addParentNodeBreadcrumbs($nodeId, $onlyAddTopParent = false) { try { // obtain crumbs $nodeLibrary = vB_Library::instance('node'); $nodeParents = $nodeLibrary->getNodeParents($nodeId); $nodeParentsReversed = array_reverse($nodeParents); $parentsInfo = $nodeLibrary->getNodes($nodeParentsReversed); $routeIds = array(); foreach ($nodeParentsReversed as $parentId) { if ($parentId != 1) { $routeIds[] = $parentsInfo[$parentId]['routeid']; if ($onlyAddTopParent) { break; } } } vB5_Route::preloadRoutes($routeIds); foreach ($nodeParentsReversed as $parentId) { if ($parentId != 1) { $this->breadcrumbs[] = array('title' => $parentsInfo[$parentId]['title'], 'url' => vB5_Route::buildUrl($parentsInfo[$parentId]['routeid'])); if ($onlyAddTopParent) { break; } } } } catch (vB_Exception $e) { // if we don't have permissions to view the channel, then skip this } }
/** gets Get info on every SG Channel * * @param array Array of options to filter the info (used to show all/my groups). * @param array Array of route info of the social group parent channel to be used for building pagination URLs. * @return mixed Array containing the social group channel info we need. */ public function getSGInfo($options = array(), $routeInfo = array()) { $response = array(); $nodeApi = vB_Api::instanceInternal('node'); $sgParentChannel = $this->getSGChannel(); if (!empty($options['sgparent']) and intval($options['sgparent']) and intval($options['sgparent'] != $sgParentChannel)) { $sgParent = intval($options['sgparent']); $depth = 1; } else { $sgParent = $sgParentChannel; $depth = 2; } // category check if (!$this->isSGNode($sgParent)) { throw new vB_Exception_Api('invalid_sg_parent'); } //Get base data $channelContentType = vB_Types::instance()->getContentTypeId('vBForum_Channel'); $params = array('starter_only' => 1, 'view' => 'activity', 'depth_exact' => 1, 'nolimit' => 1); $queryParams = array('sgParentChannel' => $sgParent, 'depth' => $depth); if (!empty($options['userid'])) { $queryParams['userid'] = $params['userid'] = intval($options['userid']); } $page = (!empty($options['page']) and intval($options['page'])) ? intval($options['page']) : 1; $perpage = (!empty($options['perpage']) and intval($options['perpage'])) ? intval($options['perpage']) : 20; $cacheParams = array_merge($params, array('page' => $page, 'perpage' => $perpage, 'sgparent' => $sgParent, 'depth' => $depth)); $cacheKey = 'sgResults_' . (vB::getUserContext()->fetchUserId() ? vB::getUserContext()->fetchUserId() : 0) . crc32(serialize($cacheParams)); if ($result = vB_Cache::instance(vB_Cache::CACHE_FAST)->read($cacheKey) or !vB::getUserContext()->hasPermission('socialgrouppermissions', 'canviewgroups')) { //we don't cache the pagination URLs as they may vary for the same content depending on the specified routeInfo (routeId, arguments, queryParameters) $pageInfo = $result['pageInfo']; $paginationURLs = $this->buildPaginationURLs($pageInfo['currentpage'], $pageInfo['totalpages'], $routeInfo); if ($paginationURLs) { $pageInfo = array_merge($pageInfo, $paginationURLs); $result['pageInfo'] = $pageInfo; } return $result; } $nodeContent = $nodeApi->listNodeContent($sgParent, $page, $perpage, $depth, $channelContentType, $params); $totalCount = vB::getDbAssertor()->getRow('vBForum:getSocialGroupsTotalCount', $queryParams); //We need the nodeids to collect some data $cacheEvents = array('nodeChg_' . $sgParent); $lastids = array(); $lastNodes = array(); $channelids = array(); $categories = array(); $contributorIds = array(); $sgCategories = array_keys($this->getCategories()); $sgParentChannel = $this->getSGChannel(); foreach ($nodeContent as $key => $node) { if ($node['parentid'] == $sgParentChannel) { $categories[] = $node['nodeid']; unset($nodeContent[$node['nodeid']]); } else { if ($node['lastcontentid'] > 0) { $lastids[] = $node['lastcontentid']; } if (in_array($node['parentid'], $sgCategories)) { $categories[] = $node['parentid']; } $channelids[] = $node['nodeid']; $contributorIds[] = $node['userid']; $cacheEvents[] = 'nodeChg_' . $node['nodeid']; } } $categories = array_unique($categories); if (empty($channelids)) { //for display purposes, we set totalpages to 1 even if there are no records because we don't want the UI to display Page 1 of 0 $result = array('results' => array(), 'totalcount' => 0, 'pageInfo' => array('currentpage' => $page, 'perpage' => $perpage, 'nexturl' => '', 'prevurl' => '', 'totalpages' => 1, 'totalrecords' => 0, 'sgparent' => $sgParent)); vB_Cache::instance(vB_Cache::CACHE_FAST)->write($cacheKey, $result, 60, array_unique($cacheEvents)); return $result; } $mergedNodes = vB_Library::instance('node')->getNodes($lastids + $categories); foreach ($lastids as $lastid) { if (empty($mergedNodes[$lastid])) { continue; } $lastNodes[$lastid] = $mergedNodes[$lastid]; } foreach ($categories as $category) { if (empty($mergedNodes[$category])) { continue; } $categoriesInfo[$category] = $mergedNodes[$category]; } // update category info foreach ($nodeContent as $key => $node) { // add category info if (isset($categoriesInfo[$node['parentid']])) { $nodeContent[$key]['content']['channeltitle'] = $categoriesInfo[$node['parentid']]['title']; $nodeContent[$key]['content']['channelroute'] = $categoriesInfo[$node['parentid']]['routeid']; $cacheEvents[] = 'nodeChg_' . $node['parentid']; } } $lastTitles = $lastInfo = array(); $lastIds = array(); foreach ($lastNodes as $lastnode) { $lastInfo[$lastnode['nodeid']]['starter'] = $lastnode['starter']; if ($lastnode['starter'] == $lastnode['nodeid']) { $lastInfo[$lastnode['nodeid']]['title'] = $lastnode['title']; $lastInfo[$lastnode['nodeid']]['routeid'] = $lastnode['routeid']; $contributorIds[] = $lastnode['userid']; } else { //We need another query $lastIds[$lastnode['starter']] = $lastnode['starter']; } } //Now get any lastcontent starter information we need if (!empty($lastIds)) { $nodes = vB_Library::instance('node')->getNodes($lastIds); foreach ($nodeContent as $index => $channel) { $nodeid = $lastInfo[$channel['lastcontentid']]['starter']; if (isset($nodes[$nodeid])) { $node =& $nodes[$nodeid]; $lastInfo[$channel['lastcontentid']]['routeid'] = $node['routeid']; $lastInfo[$channel['lastcontentid']]['title'] = $node['title']; } } } if (!empty($options['contributors'])) { //Get contributors $groups = vB::getDbAssertor()->getColumn('vBForum:usergroup', 'usergroupid', array('systemgroupid' => array(vB_Api_UserGroup::CHANNEL_MODERATOR_SYSGROUPID, vB_Api_UserGroup::CHANNEL_MEMBER_SYSGROUPID, vB_Api_UserGroup::CHANNEL_OWNER_SYSGROUPID)), false, 'systemgroupid'); $membersQry = vB::getDbAssertor()->assertQuery('vBForum:groupintopic', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'nodeid' => $channelids, 'groupid' => $groups)); $groupManagers = array(); $contributors = array(); foreach ($membersQry as $record) { if ($record['groupid'] == $groups[vB_Api_UserGroup::CHANNEL_MODERATOR_SYSGROUPID]) { $groupManagers[] = $record; } $contributorIds[$record['userid']] = $record['userid']; $cacheEvents[] = 'sgMemberChg_' . $record['userid']; } $userApi = vB_Api::instanceInternal('user'); $avatarInfo = vB_Api::instanceInternal('user')->fetchAvatars($contributorIds); foreach ($groupManagers as $index => $contributor) { if (!isset($contributors[$contributor['nodeid']])) { $contributors[$contributor['nodeid']] = array(); } $userInfo = $userApi->fetchUserinfo($contributor['userid']); $contributors[$contributor['nodeid']][$contributor['userid']] = $userInfo; $contributors[$contributor['nodeid']][$contributor['userid']]['avatar'] = $avatarInfo[$contributor['userid']]; } } // Obtain keys for sg pages $pageKeyInfo = array(); $routes = vB::getDbAssertor()->getRows('routenew', array('class' => 'vB5_Route_Channel', 'contentid' => $channelids), false, 'routeid'); vB5_Route::preloadRoutes(array_keys($routes)); foreach ($routes as $record) { $route = vB5_Route_Channel::getRoute($record['routeid'], @unserialize($record['arguments'])); if ($route and $pageKey = $route->getPageKey()) { $pageKeyInfo[$pageKey] = $record['contentid']; } } $viewingQry = vB::getDbAssertor()->getRows('session', array(vB_dB_Query::TYPE_KEY => vB_dB_Query::QUERY_SELECT, 'pagekey' => array_keys($pageKeyInfo))); $viewing = array(); foreach ($viewingQry as $viewingUser) { if (!isset($viewing[$viewingUser['nodeid']])) { $viewing[$viewingUser['nodeid']] = 0; } $viewing[$viewingUser['nodeid']]++; } // get the members count $countRecords = vB::getDbAssertor()->assertQuery('vBForum:getChannelMembersCount', array('nodeid' => $channelids, 'groupid' => $groups)); $membersCount = array(); foreach ($countRecords as $count) { $membersCount[$count['nodeid']] = $count; } foreach ($nodeContent as $index => $channel) { $nodeid = $channel['nodeid']; if (!empty($options['contributors'])) { $nodeContent[$index]['contributors'] = !empty($contributors[$nodeid]) ? $contributors[$nodeid] : 0; $nodeContent[$index]['contributorscount'] = !empty($contributors[$nodeid]) ? count($contributors[$nodeid]) : 0; } $nodeContent[$index]['members'] = !empty($membersCount[$nodeid]) ? $membersCount[$nodeid]['members'] : 0; $nodeContent[$index]['viewing'] = !empty($viewing[$nodeid]) ? $viewing[$nodeid] : 0; $nodeContent[$index]['lastposttitle'] = !empty($lastInfo[$channel['lastcontentid']]['title']) ? $lastInfo[$channel['lastcontentid']]['title'] : 0; $nodeContent[$index]['lastpostrouteid'] = !empty($lastInfo[$channel['lastcontentid']]['routeid']) ? $lastInfo[$channel['lastcontentid']]['routeid'] : 0; $nodeContent[$index]['owner_avatar'] = $avatarInfo[$nodeContent[$index]['userid']]; $nodeContent[$index]['lastauthor_avatar'] = $avatarInfo[$nodeContent[$index]['lastauthorid']]; } $total = $totalCount['totalcount']; if ($total > 0) { $pages = ceil($total / $perpage); } else { $pages = 1; //we don't want the UI to display Page 1 of 0 } $pageInfo = array('currentpage' => $page, 'perpage' => $perpage, 'prevurl' => '', 'nexturl' => '', 'totalpages' => $pages, 'totalrecords' => $total, 'sgparent' => $sgParent); $result = array('results' => $nodeContent, 'totalcount' => count($nodeContent), 'pageInfo' => $pageInfo); vB_Cache::instance(vB_Cache::CACHE_FAST)->write($cacheKey, $result, 60, array_unique($cacheEvents)); //we don't cache the pagination URLs as they may vary for the same content depending on the specified routeInfo (routeId, arguments, queryParameters) $paginationURLs = $this->buildPaginationURLs($page, $pages, $routeInfo); if ($paginationURLs) { $pageInfo = array_merge($pageInfo, $paginationURLs); $result['pageInfo'] = $pageInfo; } return $result; }
/** * Takes an array of node information and adds contentInfo * @param integer The node id of the parent where we are listing * @param integer page number to return * @param integer items per page * @param integer depth- 0 means no stopping, otherwise 1= direct child, 2= grandchild, etc * @param mixed if desired, will only return specific content types. * @param mixed 'sort', or 'exclude' recognized. * * @return mixed array of id's ***/ public function addFullContentInfo($nodeList, $options = array()) { //Now separate by content type $contenttypes = array(); if (empty($nodeList)) { return array(); } $nodeIds = array(); $needVote = array(); $cacheVote = array(); $needRead = array(); $parentids = array(); $attachCounts = array(); $photoCounts = array(); $channels = array(); $grabAttachCounts = array(); $cache = vB_Cache::instance(vB_Cache::CACHE_FAST); $userids = array(); foreach ($nodeList as $key => $node) { if (empty($node['nodeid'])) { continue; } if (!isset($contenttypes[$node['contenttypeid']])) { $contenttypes[$node['contenttypeid']] = array(); } $contenttypes[$node['contenttypeid']][$key] = $node['nodeid']; $nodeIds[] = $node['nodeid']; if ($this->channelTypeId != $node['contenttypeid']) { // only fetch attachments for non channels. $grabAttachCounts[] = $node['nodeid']; } if (!isset($node['nodeVoted'])) { $needVote[] = $node['nodeid']; } else { $cacheVote[$node['nodeid']] = $node['nodeVoted']; } if (!isset($node['readtime'])) { $needRead[$node['nodeid']] = $node['nodeid']; $nodeList[$key]['readtime'] = 0; } $parentids[$node['parentid']] = $node['parentid']; $needRead = array_merge($parentids, $needRead); if (!isset($userids[$node['userid']])) { $userids[$node['userid']] = $node['userid']; } } vB_Library::instance('user')->preloadUserInfo($userids); // pre-cache parents $parents = $this->getNodes($parentids); $parentrouteids = array(); foreach ($parents as $parent) { $parentrouteids[] = $parent['routeid']; } //pre-load parent routes vB5_Route::preloadRoutes($parentrouteids); // get votes $nodeVotes = empty($needVote) ? array() : $this->getNodeVotes($needVote); if (!empty($cacheVote)) { $this->cacheNodeVotes($cacheVote); } if (!empty($nodeIds)) { $attachments = $this->fetchNodeAttachments($nodeIds); $nodeAttachments = array(); foreach ($attachments as $key => $attach) { $nodeAttachments[$attach['parentid']][$attach['filedataid']] =& $attachments[$key]; } } // Fetch read marking data $threadmarking = vB::getDatastore()->getOption('threadmarking'); $userid = vB::getCurrentSession()->get('userid'); if ($threadmarking and $userid and !empty($nodeIds) and !empty($needRead)) { $reads = vB::getDbAssertor()->getRows('noderead', array('userid' => $userid, 'nodeid' => $needRead)); $parentsreads = array(); foreach ($reads as $read) { if (!empty($nodeList[$read['nodeid']])) { $nodeList[$read['nodeid']]['readtime'] = $read['readtime']; } else { $parentsreads[$read['nodeid']] = $read['readtime']; } } foreach ($nodeList as $nodeid => $node) { if (empty($parentsreads[$node['parentid']])) { $parentsreads[$node['parentid']] = 0; } $nodeList[$nodeid]['parentreadtime'] = $parentsreads[$node['parentid']]; } } //For each type, get the content detail. if (!empty($grabAttachCounts)) { $attachCountQry = vB::getDbAssertor()->getRows('vBForum:getDescendantAttachCount', array('nodeid' => $grabAttachCounts)); foreach ($attachCountQry as $count) { $attachCounts[$count['nodeid']] = $count['count']; } $photoCountQry = vB::getDbAssertor()->getRows('vBForum:getDescendantPhotoCount', array('nodeid' => $grabAttachCounts, 'photoTypeid' => vB_Types::instance()->getContentTypeID('vBForum_Photo'))); foreach ($photoCountQry as $count) { $photoCounts[$count['nodeid']] = $count['count']; } } // precache closure $this->fetchClosureParent($nodeIds); $optionMask = vB_Api::instanceInternal('node')->getOptions(); foreach ($contenttypes as $contenttypeid => $nodes) { if (!empty($nodes)) { $contentLib = vB_Library_Content::getContentLib($contenttypeid); $contentList = $contentLib->getFullContent($nodes); foreach ($nodes as $key => $nodeid) { if (isset($contentList[$nodeid])) { if (!empty($contentList[$nodeid]['node_no_permission'])) { unset($nodeList[$nodeid]); continue; } if (isset($nodeList[$key]['nodeVoted'])) { // node came into the function with nodeVoted already set $contentList[$nodeid]['nodeVoted'] = $nodeList[$key]['nodeVoted']; } else { // node came into this function w/o nodeVoted set so getNodeVotes retrieved it up there^ $contentList[$nodeid]['nodeVoted'] = in_array($nodeid, $nodeVotes) ? 1 : 0; } $nodeList[$key]['content'] = $contentList[$nodeid]; if (!empty($contentList[$nodeid]['contenttypeclass'])) { $nodeList[$key]['contenttypeclass'] = $contentList[$nodeid]['contenttypeclass']; } if ($contentList[$nodeid]['contenttypeid'] == $this->channelTypeId) { $channels[$contentList[$nodeid]['nodeid']] = $contentList[$nodeid]['nodeid']; } else { if (!empty($contentList[$nodeid]['channelid']) and !isset($channels[$contentList[$nodeid]['channelid']])) { $channels[$contentList[$nodeid]['channelid']] = $contentList[$nodeid]['channelid']; } } } foreach ($optionMask as $bitname => $bitmask) { $nodeList[$key][$bitname] = $bitmask & $node['nodeoptions'] ? 1 : 0; } if (isset($nodeAttachments[$nodeid])) { $nodeList[$key]['content']['attachments'] =& $nodeAttachments[$nodeid]; } else { $nodeList[$key]['content']['attachments'] = array(); } if (empty($attachCounts[$nodeid])) { $nodeList[$key]['attachcount'] = 0; } else { $nodeList[$key]['attachcount'] = $attachCounts[$nodeid]; } if (!empty($photoCounts[$nodeid])) { $nodeList[$key]['attachcount'] += $photoCounts[$nodeid]; } } } } // censor textual node items vB_Library_Node::censorNodes($nodeList); $this->addOptionalContentInfo($nodeList, $options); //Note- it is essential that the parentids be passed along with the nodeList. This allows all the permissions to // be pulled in one function call, and saves a lot of processing in the usercontext object. $this->markSubscribed($nodeList); $this->markJoined($nodeList); return $nodeList; }
/** Preloads a list of routes to reduce database traffic * * @param mixed array of route ids- can be integers or strings. **/ public function preloadRoutes($routeIds) { return vB5_Route::preloadRoutes($routeIds); }