/** * @return PostRevision[] * @throws DataModelException */ public function getChildren() { if ($this->children === null) { throw new DataModelException('Children not loaded for post: ' . $this->postId->getAlphadecimal(), 'process-data'); } return $this->children; }
public function doQuery() { $direction = $this->mIsBackwards ? 'rev' : 'fwd'; // over-fetch so we can figure out if there's anything after what we're showing $this->mResult = $this->query->getResults($this->id, $this->getLimit() + 1, $this->mOffset, $direction); if (!$this->mResult) { throw new InvalidDataException('Unable to load history for ' . $this->id->getAlphadecimal(), 'fail-load-history'); } $this->mQueryDone = true; // we over-fetched, now get rid of redundant value for our "real" data $overfetched = null; if (count($this->mResult) > $this->getLimit()) { // when traversing history reverse, the overfetched entry will be at // the beginning of the list; in normal mode it'll be last if ($this->mIsBackwards) { $overfetched = array_shift($this->mResult); } else { $overfetched = array_pop($this->mResult); } } // set some properties that'll be used to generate navigation bar $this->mLastShown = $this->mResult[count($this->mResult) - 1]->revision->getRevisionId()->getAlphadecimal(); $this->mFirstShown = $this->mResult[0]->revision->getRevisionId()->getAlphadecimal(); /* * By overfetching, we've already figured out if there's additional * entries at the next page (according to the current direction). Now * go fetch 1 more in the other direction (the one we likely came from, * when navigating) */ $nextOffset = $this->mIsBackwards ? $this->mFirstShown : $this->mLastShown; $nextOffset = UUID::create($nextOffset); $reverseDirection = $this->mIsBackwards ? 'fwd' : 'rev'; $this->mIsLast = !$overfetched; $this->mIsFirst = !$this->mOffset || count($this->query->getResults($this->id, 1, $nextOffset, $reverseDirection)) === 0; if ($this->mIsBackwards) { // swap values if we're going backwards list($this->mIsFirst, $this->mIsLast) = array($this->mIsLast, $this->mIsFirst); // id of the overfetched entry, used to build new links starting at // this offset if ($overfetched) { $this->mPastTheEndIndex = $overfetched->revision->getRevisionId()->getAlphadecimal(); } } }
/** * Returns the revision with the given id. * * @param UUID $uuid * @return AbstractRevision|null null if there is no such revision */ public function getRevision(UUID $uuid) { // check if fetching last already res if (isset($this->revisions[$uuid->getAlphadecimal()])) { return $this->revisions[$uuid->getAlphadecimal()]; } /* * The strategy here is to avoid having to call getAllRevisions(), which * is most likely to have to load (fresh) data that is not yet in * LocalBufferedCache's internal cache. * To do so, we'll build the $this->revisions array by hand. Starting at * the most recent revision and going up 1 revision at a time, checking * if it is already in LocalBufferedCache's cache. * If, however, we can't find the requested revisions (or one of the * revisions on our way to the requested revision) in the internal cache * of LocalBufferedCache, we'll just bail and load all revisions after * all: if we do have to fetch data, might as well do it all in 1 go! */ while (!$this->loaded()) { // fetch current oldest revision $oldest = $this->getOldestLoaded(); // fetch that one's preceding revision id $previousId = $oldest->getPrevRevisionId(); // check if it's in local storage already if ($previousId && $this->getStorage()->got($previousId)) { $revision = $this->getStorage()->get($previousId); // add this revision to revisions array $this->revisions[$previousId->getAlphadecimal()] = $revision; // stop iterating if we've found the one we wanted if ($uuid->equals($previousId)) { break; } } else { // revision not found in local storage: load all revisions $this->getAllRevisions(); break; } } if (!isset($this->revisions[$uuid->getAlphadecimal()])) { return null; } return $this->revisions[$uuid->getAlphadecimal()]; }
public function getResult(UUID $uuid) { $alpha = $uuid->getAlphadecimal(); // Minimal set of data needed for the CategoryViewFormatter $row = new FormatterRow(); if (!isset($this->posts[$alpha])) { throw new FlowException("A required post has not been loaded: {$alpha}"); } $row->revision = reset($this->posts[$alpha]); if (!isset($this->workflows[$alpha])) { throw new FlowException("A required workflow has not been loaded: {$alpha}"); } $row->workflow = $this->workflows[$alpha]; return $row; }
/** * Return the title this workflow responds at * * @return Title * @throws CrossWikiException */ public function getArticleTitle() { if ($this->title) { return $this->title; } // evil hax if ($this->type === 'topic') { $namespace = NS_TOPIC; $titleText = $this->id->getAlphadecimal(); } else { $namespace = $this->namespace; $titleText = $this->titleText; } return $this->title = self::getFromTitleCache($this->wiki, $namespace, $titleText); }
/** * Adds a moderation activity item to the log under the appropriate action * * @param PostRevision $post * @param string $action The action we'll be logging * @param string $reason Comment, reason for the moderation * @param UUID $workflowId Workflow being worked on * @return int The id of the newly inserted log entry */ public function log(PostRevision $post, $action, $reason, UUID $workflowId) { if (!$this->canLog($post, $action)) { return null; } $params = array('topicId' => $workflowId->getAlphadecimal()); if (!$post->isTopicTitle()) { $params['postId'] = $post->getPostId()->getAlphadecimal(); } $logType = $this->getLogType($post, $action); // reasonably likely this is already loaded in-process and just returns that object /** @var Workflow $workflow */ $workflow = Container::get('storage.workflow')->get($workflowId); if ($workflow) { $title = $workflow->getArticleTitle(); } else { $title = false; } $error = false; if (!$title) { // We dont want to fail logging due to this, so repoint it at Main_Page which // will probably be noticed, also log it below once we know the logId $title = Title::newMainPage(); $error = true; } // insert logging entry $logEntry = new ManualLogEntry($logType, "flow-{$action}"); $logEntry->setTarget($title); $logEntry->setPerformer($post->getUserTuple()->createUser()); $logEntry->setParameters($params); $logEntry->setComment($reason); $logEntry->setTimestamp($post->getModerationTimestamp()); $logId = $logEntry->insert(); if ($error) { wfDebugLog('Flow', __METHOD__ . ': Could not map workflowId to workflow object for ' . $workflowId->getAlphadecimal() . " log entry {$logId} defaulted to Main_Page"); } return $logId; }
/** * Finds the RecentChange object associated with this flow revision. * * @return null|RecentChange */ public function getRecentChange() { $timestamp = $this->revId->getTimestamp(); if (!RecentChange::isInRCLifespan($timestamp)) { // Too old to be in RC, don't even bother checking return null; } $workflow = $this->getCollection()->getWorkflow(); if ($this->changeType === 'new-post') { $title = $workflow->getOwnerTitle(); } else { $title = $workflow->getArticleTitle(); } $namespace = $title->getNamespace(); $conditions = array('rc_title' => $title->getDBkey(), 'rc_timestamp' => $timestamp, 'rc_namespace' => $namespace); $options = array('USE INDEX' => 'rc_timestamp'); $dbr = wfGetDB(DB_SLAVE); $rows = $dbr->select('recentchanges', RecentChange::selectFields(), $conditions, __METHOD__, $options); if ($rows === false) { return null; } if ($rows->numRows() === 1) { return RecentChange::newFromRow($rows->fetchObject()); } // it is possible that more than 1 changes on the same page have the same timestamp // the revision id is hidden in rc_params['flow-workflow-change']['revision'] $revId = $this->revId->getAlphadecimal(); while ($row = $rows->next()) { $rc = RecentChange::newFromRow($row); $params = $rc->parseParams(); if ($params && $params['flow-workflow-change']['revision'] === $revId) { return $rc; } } return null; }
public function setContentFormat($format, UUID $revisionId = null) { if (false === array_search($format, $this->allowedContentFormats)) { throw new FlowException("Unknown content format: {$format}"); } if ($revisionId === null) { // set default content format $this->contentFormat = $format; } else { // set per-revision content format $this->revisionContentFormat[$revisionId->getAlphadecimal()] = $format; } }
/** * Suppress the specified post within the specified workflow * * @param Title|null $title * @param UUID $workflowId * @param UUID $postId * @return Anchor */ public function suppressPostAction(Title $title = null, UUID $workflowId, UUID $postId) { return new Anchor(wfMessage('flow-post-action-suppress-post'), $this->resolveTitle($title, $workflowId), array('action' => 'moderate-post', 'topic_postId' => $postId->getAlphadecimal(), 'topic_moderationState' => AbstractRevision::MODERATED_SUPPRESSED)); }
/** * Returns the revision with the given id. * * @param UUID $uuid * @return AbstractRevision|null null if there is no such revision */ public function getRevision(UUID $uuid) { // make sure all revisions have been loaded $this->getAllRevisions(); if (!isset($this->revisions[$uuid->getAlphadecimal()])) { return null; } // find requested id, based on given revision return $this->revisions[$uuid->getAlphadecimal()]; }
/** * Finds the root path for a single post ID. * @param UUID $descendant Post ID * @return UUID[]|null Path to the root of that node. */ public function findRootPath(UUID $descendant) { $paths = $this->findRootPaths(array($descendant)); return isset($paths[$descendant->getAlphadecimal()]) ? $paths[$descendant->getAlphadecimal()] : null; }
/** * @param UUID|null $other * @return boolean */ public function equals(UUID $other = null) { return $other && $other->getAlphadecimal() === $this->getAlphadecimal(); }
/** * Returns the storage row for this Reference. * For this abstract reference, only partial. * * @return array */ public function getStorageRow() { return array('ref_src_workflow_id' => $this->workflowId->getAlphadecimal(), 'ref_src_namespace' => $this->srcTitle->getNamespace(), 'ref_src_title' => $this->srcTitle->getDBkey(), 'ref_src_object_type' => $this->objectType, 'ref_src_object_id' => $this->objectId->getAlphadecimal(), 'ref_type' => $this->type); }
public function setAssociation(UUID $objectId, $importSourceKey) { $this->data[$importSourceKey] = $objectId->getAlphadecimal(); }
/** * Gets a Workflow object given its ID * @param UUID $workflowId The Workflow ID to retrieve. * @return Workflow The Workflow. */ protected function getWorkflowById(UUID $workflowId) { $alpha = $workflowId->getAlphadecimal(); if (isset($this->workflowCache[$alpha])) { return $this->workflowCache[$alpha]; } else { return $this->workflowCache[$alpha] = $this->storage->get('Workflow', $workflowId); } }