/**
  * @see EntityRedirectLookup::getRedirectForEntityId
  *
  * @since 0.5
  *
  * @param EntityId $entityId
  * @param string $forUpdate
  *
  * @return EntityId|null The ID of the redirect target, or null if $entityId
  *         does not refer to a redirect
  * @throws EntityRedirectLookupException
  */
 public function getRedirectForEntityId(EntityId $entityId, $forUpdate = '')
 {
     try {
         $title = $this->entityTitleLookup->getTitleForId($entityId);
     } catch (\Exception $ex) {
         // TODO: catch more specific type of exception once EntityTitleLookup contract is clarified
         throw new EntityRedirectLookupException($entityId, null, $ex);
     }
     $forUpdate = $forUpdate === 'for update' ? DB_MASTER : DB_SLAVE;
     try {
         $db = $this->loadBalancer->getConnection($forUpdate);
     } catch (MWException $ex) {
         throw new EntityRedirectLookupException($entityId, null, $ex);
     }
     $row = $db->selectRow(array('page', 'redirect'), array('page_id', 'rd_namespace', 'rd_title'), array('page_title' => $title->getDBkey(), 'page_namespace' => $title->getNamespace()), __METHOD__, array(), array('redirect' => array('LEFT JOIN', 'rd_from=page_id')));
     try {
         $this->loadBalancer->reuseConnection($db);
     } catch (MWException $ex) {
         throw new EntityRedirectLookupException($entityId, null, $ex);
     }
     if (!$row) {
         throw new EntityRedirectLookupException($entityId);
     }
     if ($row->rd_namespace === null) {
         return null;
     }
     $title = Title::makeTitle($row->rd_namespace, $row->rd_title);
     return $this->entityIdLookup->getEntityIdForTitle($title);
 }
 /**
  * @param ChangesList $list
  * @param ResultWrapper|array $rows
  *
  * @return bool
  */
 public function doChangesListInitRows(ChangesList $list, $rows)
 {
     try {
         $titles = $this->getChangedTitles($rows);
         $entityIds = $this->idLookup->getEntityIds($titles);
         $this->buffer->prefetchTerms($entityIds, $this->termTypes, $this->languageCodes);
     } catch (StorageException $ex) {
         wfLogWarning(__METHOD__ . ': ' . $ex->getMessage());
     }
     return true;
 }
 /**
  * @param Title $target
  * @param string &$html
  * @param array &$customAttribs
  * @param RequestContext $context
  */
 public function doOnLinkBegin(Title $target, &$html, array &$customAttribs, RequestContext $context)
 {
     $out = $context->getOutput();
     if (!$this->entityNamespaceLookup->isEntityNamespace($target->getNamespace())) {
         return;
     }
     // Only continue on pages with edit summaries (histories / diffs) or on special pages.
     // Don't run this code when accessing it through the api (eg. for parsing) as the title is
     // set to a special page dummy in api.php, see https://phabricator.wikimedia.org/T111346
     if (defined('MW_API') || !$this->shouldConvert($out->getTitle(), $context)) {
         return;
     }
     $targetText = $target->getText();
     // Handle "fake" titles for new entities as generated by
     // EditEntity::getContextForEditFilter(). For instance, a link to Property:NewProperty
     // would be replaced by a link to Special:NewProperty. This is useful in logs,
     // to indicate that the logged action occurred while creating an entity.
     if (SpecialPageFactory::exists($targetText)) {
         $target = Title::makeTitle(NS_SPECIAL, $targetText);
         $html = Linker::linkKnown($target);
         return;
     }
     if (!$target->exists()) {
         // The link points to a non-existing item.
         return;
     }
     // if custom link text is given, there is no point in overwriting it
     // but not if it is similar to the plain title
     if ($html !== null && $target->getFullText() !== $html) {
         return;
     }
     $entityId = $this->entityIdLookup->getEntityIdForTitle($target);
     if (!$entityId) {
         return;
     }
     // @todo: this re-implements the logic in LanguageFallbackLabelDescriptionLookup,
     // as that didn't support descriptions back when this code was written.
     // NOTE: keep in sync with with fallback languages in LabelPrefetchHookHandler::newFromGlobalState
     try {
         $labels = $this->termLookup->getLabels($entityId, $this->languageFallback->getFetchLanguageCodes());
         $descriptions = $this->termLookup->getDescriptions($entityId, $this->languageFallback->getFetchLanguageCodes());
     } catch (StorageException $ex) {
         // This shouldn't happen if $target->exists() return true!
         return;
     }
     $labelData = $this->getPreferredTerm($labels);
     $descriptionData = $this->getPreferredTerm($descriptions);
     $html = $this->getHtml($target, $labelData);
     $customAttribs['title'] = $this->getTitleAttribute($target, $labelData, $descriptionData);
     // add wikibase styles in all cases, so we can format the link properly:
     $out->addModuleStyles(array('wikibase.common'));
 }
 /**
  * @param Title[] $titles
  * @param int|null $continue
  *
  * @return array
  */
 private function getEntityIdsForTitles(array $titles, $continue = 0)
 {
     $entityIds = $this->idLookup->getEntityIds($titles);
     // Re-sort, so the order of page IDs matches the order in which $titles
     // were given. This is essential for paging to work properly.
     // This also skips all page IDs up to $continue.
     $sortedEntityId = array();
     foreach ($titles as $pid => $title) {
         if ($pid >= $continue && isset($entityIds[$pid])) {
             $sortedEntityId[$pid] = $entityIds[$pid];
         }
     }
     return $sortedEntityId;
 }