Path: blob/master/src/applications/conpherence/query/ConpherenceThreadQuery.php
12262 views
<?php12final class ConpherenceThreadQuery3extends PhabricatorCursorPagedPolicyAwareQuery {45const TRANSACTION_LIMIT = 100;67private $phids;8private $ids;9private $participantPHIDs;10private $needParticipants;11private $needTransactions;12private $afterTransactionID;13private $beforeTransactionID;14private $transactionLimit;15private $fulltext;16private $needProfileImage;1718public function needParticipants($need) {19$this->needParticipants = $need;20return $this;21}2223public function needProfileImage($need) {24$this->needProfileImage = $need;25return $this;26}2728public function needTransactions($need_transactions) {29$this->needTransactions = $need_transactions;30return $this;31}3233public function withIDs(array $ids) {34$this->ids = $ids;35return $this;36}3738public function withPHIDs(array $phids) {39$this->phids = $phids;40return $this;41}4243public function withParticipantPHIDs(array $phids) {44$this->participantPHIDs = $phids;45return $this;46}4748public function setAfterTransactionID($id) {49$this->afterTransactionID = $id;50return $this;51}5253public function setBeforeTransactionID($id) {54$this->beforeTransactionID = $id;55return $this;56}5758public function setTransactionLimit($transaction_limit) {59$this->transactionLimit = $transaction_limit;60return $this;61}6263public function getTransactionLimit() {64return $this->transactionLimit;65}6667public function withFulltext($query) {68$this->fulltext = $query;69return $this;70}7172public function withTitleNgrams($ngrams) {73return $this->withNgramsConstraint(74id(new ConpherenceThreadTitleNgrams()),75$ngrams);76}7778protected function loadPage() {79$table = new ConpherenceThread();80$conn_r = $table->establishConnection('r');8182$data = queryfx_all(83$conn_r,84'SELECT thread.* FROM %T thread %Q %Q %Q %Q %Q',85$table->getTableName(),86$this->buildJoinClause($conn_r),87$this->buildWhereClause($conn_r),88$this->buildGroupClause($conn_r),89$this->buildOrderClause($conn_r),90$this->buildLimitClause($conn_r));9192$conpherences = $table->loadAllFromArray($data);9394if ($conpherences) {95$conpherences = mpull($conpherences, null, 'getPHID');96$this->loadParticipantsAndInitHandles($conpherences);97if ($this->needParticipants) {98$this->loadCoreHandles($conpherences, 'getParticipantPHIDs');99}100if ($this->needTransactions) {101$this->loadTransactionsAndHandles($conpherences);102}103if ($this->needProfileImage) {104$default = null;105$file_phids = mpull($conpherences, 'getProfileImagePHID');106$file_phids = array_filter($file_phids);107if ($file_phids) {108$files = id(new PhabricatorFileQuery())109->setParentQuery($this)110->setViewer($this->getViewer())111->withPHIDs($file_phids)112->execute();113$files = mpull($files, null, 'getPHID');114} else {115$files = array();116}117118foreach ($conpherences as $conpherence) {119$file = idx($files, $conpherence->getProfileImagePHID());120if (!$file) {121if (!$default) {122$default = PhabricatorFile::loadBuiltin(123$this->getViewer(),124'conpherence.png');125}126$file = $default;127}128$conpherence->attachProfileImageFile($file);129}130}131}132133return $conpherences;134}135136protected function buildGroupClause(AphrontDatabaseConnection $conn_r) {137if ($this->participantPHIDs !== null138|| ($this->fulltext !== null && strlen($this->fulltext))) {139return qsprintf($conn_r, 'GROUP BY thread.id');140} else {141return $this->buildApplicationSearchGroupClause($conn_r);142}143}144145protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {146$joins = parent::buildJoinClauseParts($conn);147148if ($this->participantPHIDs !== null) {149$joins[] = qsprintf(150$conn,151'JOIN %T p ON p.conpherencePHID = thread.phid',152id(new ConpherenceParticipant())->getTableName());153}154155if ($this->fulltext !== null && strlen($this->fulltext)) {156$joins[] = qsprintf(157$conn,158'JOIN %T idx ON idx.threadPHID = thread.phid',159id(new ConpherenceIndex())->getTableName());160}161162// See note in buildWhereClauseParts() about this optimization.163$viewer = $this->getViewer();164if (!$viewer->isOmnipotent() && $viewer->isLoggedIn()) {165$joins[] = qsprintf(166$conn,167'LEFT JOIN %T vp ON vp.conpherencePHID = thread.phid168AND vp.participantPHID = %s',169id(new ConpherenceParticipant())->getTableName(),170$viewer->getPHID());171}172173return $joins;174}175176protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {177$where = parent::buildWhereClauseParts($conn);178179// Optimize policy filtering of private rooms. If we are not looking for180// particular rooms by ID or PHID, we can just skip over any rooms with181// "View Policy: Room Participants" if the viewer isn't a participant: we182// know they won't be able to see the room.183// This avoids overheating browse/search queries, since it's common for184// a large number of rooms to be private and have this view policy.185$viewer = $this->getViewer();186187$can_optimize =188!$viewer->isOmnipotent() &&189($this->ids === null) &&190($this->phids === null);191192if ($can_optimize) {193$members_policy = id(new ConpherenceThreadMembersPolicyRule())194->getObjectPolicyFullKey();195$policies = array(196$members_policy,197PhabricatorPolicies::POLICY_USER,198PhabricatorPolicies::POLICY_ADMIN,199PhabricatorPolicies::POLICY_NOONE,200);201202if ($viewer->isLoggedIn()) {203$where[] = qsprintf(204$conn,205'thread.viewPolicy NOT IN (%Ls) OR vp.participantPHID = %s',206$policies,207$viewer->getPHID());208} else {209$where[] = qsprintf(210$conn,211'thread.viewPolicy NOT IN (%Ls)',212$policies);213}214}215216if ($this->ids !== null) {217$where[] = qsprintf(218$conn,219'thread.id IN (%Ld)',220$this->ids);221}222223if ($this->phids !== null) {224$where[] = qsprintf(225$conn,226'thread.phid IN (%Ls)',227$this->phids);228}229230if ($this->participantPHIDs !== null) {231$where[] = qsprintf(232$conn,233'p.participantPHID IN (%Ls)',234$this->participantPHIDs);235}236237if ($this->fulltext !== null && strlen($this->fulltext)) {238$where[] = qsprintf(239$conn,240'MATCH(idx.corpus) AGAINST (%s IN BOOLEAN MODE)',241$this->fulltext);242}243244return $where;245}246247private function loadParticipantsAndInitHandles(array $conpherences) {248$participants = id(new ConpherenceParticipant())249->loadAllWhere('conpherencePHID IN (%Ls)', array_keys($conpherences));250$map = mgroup($participants, 'getConpherencePHID');251252foreach ($conpherences as $current_conpherence) {253$conpherence_phid = $current_conpherence->getPHID();254255$conpherence_participants = idx(256$map,257$conpherence_phid,258array());259260$conpherence_participants = mpull(261$conpherence_participants,262null,263'getParticipantPHID');264265$current_conpherence->attachParticipants($conpherence_participants);266$current_conpherence->attachHandles(array());267}268269return $this;270}271272private function loadCoreHandles(273array $conpherences,274$method) {275276$handle_phids = array();277foreach ($conpherences as $conpherence) {278$handle_phids[$conpherence->getPHID()] =279$conpherence->$method();280}281$flat_phids = array_mergev($handle_phids);282$viewer = $this->getViewer();283$handles = $viewer->loadHandles($flat_phids);284$handles = iterator_to_array($handles);285foreach ($handle_phids as $conpherence_phid => $phids) {286$conpherence = $conpherences[$conpherence_phid];287$conpherence->attachHandles(288$conpherence->getHandles() + array_select_keys($handles, $phids));289}290return $this;291}292293private function loadTransactionsAndHandles(array $conpherences) {294// NOTE: This is older code which has been modernized to the minimum295// standard required by T13266. It probably isn't the best available296// approach to the problems it solves.297298$limit = $this->getTransactionLimit();299if ($limit) {300// fetch an extra for "show older" scenarios301$limit = $limit + 1;302} else {303$limit = 0xFFFF;304}305306$pager = id(new AphrontCursorPagerView())307->setPageSize($limit);308309// We have to flip these for the underlying query class. The semantics of310// paging are tricky business.311if ($this->afterTransactionID) {312$pager->setBeforeID($this->afterTransactionID);313} else if ($this->beforeTransactionID) {314$pager->setAfterID($this->beforeTransactionID);315}316317$transactions = id(new ConpherenceTransactionQuery())318->setViewer($this->getViewer())319->withObjectPHIDs(array_keys($conpherences))320->needHandles(true)321->executeWithCursorPager($pager);322323$transactions = mgroup($transactions, 'getObjectPHID');324foreach ($conpherences as $phid => $conpherence) {325$current_transactions = idx($transactions, $phid, array());326$handles = array();327foreach ($current_transactions as $transaction) {328$handles += $transaction->getHandles();329}330$conpherence->attachHandles($conpherence->getHandles() + $handles);331$conpherence->attachTransactions($current_transactions);332}333return $this;334}335336public function getQueryApplicationClass() {337return 'PhabricatorConpherenceApplication';338}339340protected function getPrimaryTableAlias() {341return 'thread';342}343344}345346347