[ Index ]

PHP Cross Reference of Phabricator

title

Body

[close]

/src/applications/search/view/ -> PhabricatorSearchResultView.php (source)

   1  <?php
   2  
   3  final class PhabricatorSearchResultView extends AphrontView {
   4  
   5    private $handle;
   6    private $query;
   7    private $object;
   8  
   9    public function setHandle(PhabricatorObjectHandle $handle) {
  10      $this->handle = $handle;
  11      return $this;
  12    }
  13  
  14    public function setQuery(PhabricatorSavedQuery $query) {
  15      $this->query = $query;
  16      return $this;
  17    }
  18  
  19    public function setObject($object) {
  20      $this->object = $object;
  21      return $this;
  22    }
  23  
  24    public function render() {
  25      $handle = $this->handle;
  26      if (!$handle->isComplete()) {
  27        return;
  28      }
  29  
  30      $type_name = nonempty($handle->getTypeName(), 'Document');
  31  
  32      require_celerity_resource('phabricator-search-results-css');
  33  
  34      $link = phutil_tag(
  35        'a',
  36        array(
  37          'href' => $handle->getURI(),
  38        ),
  39        PhabricatorEnv::getProductionURI($handle->getURI()));
  40  
  41      $img = $handle->getImageURI();
  42  
  43      if ($img) {
  44        $img = phutil_tag(
  45          'div',
  46          array(
  47            'class' => 'result-image',
  48            'style' => "background-image: url('{$img}');",
  49          ),
  50          '');
  51      }
  52  
  53      $title = $this->emboldenQuery($handle->getFullName());
  54      if ($handle->getStatus() == PhabricatorObjectHandleStatus::STATUS_CLOSED) {
  55        $title = phutil_tag('del', array(), $title);
  56      }
  57  
  58      return hsprintf(
  59        '<div class="phabricator-search-result">'.
  60          '%s'.
  61          '<div class="result-desc">'.
  62            '%s'.
  63            '<div class="result-type">%s &middot; %s</div>'.
  64          '</div>'.
  65          '<div style="clear: both;"></div>'.
  66        '</div>',
  67        $img,
  68        phutil_tag(
  69          'a',
  70          array(
  71            'class' => 'result-name',
  72            'href' => $handle->getURI(),
  73          ),
  74          $title),
  75        $type_name,
  76        $link);
  77    }
  78  
  79  
  80    /**
  81     * Find the words which are part of the query string, and bold them in a
  82     * result string. This makes it easier for users to see why a result
  83     * matched their query.
  84     */
  85    private function emboldenQuery($str) {
  86      $query = $this->query->getParameter('query');
  87  
  88      if (!strlen($query) || !strlen($str)) {
  89        return $str;
  90      }
  91  
  92      // This algorithm is safe but not especially fast, so don't bother if
  93      // we're dealing with a lot of data. This mostly prevents silly/malicious
  94      // queries from doing anything bad.
  95      if (strlen($query) + strlen($str) > 2048) {
  96        return $str;
  97      }
  98  
  99      // Keep track of which characters we're going to make bold. This is
 100      // byte oriented, but we'll make sure we don't put a bold in the middle
 101      // of a character later.
 102      $bold = array_fill(0, strlen($str), false);
 103  
 104      // Split the query into words.
 105      $parts = preg_split('/ +/', $query);
 106  
 107      // Find all occurrences of each word, and mark them to be emboldened.
 108      foreach ($parts as $part) {
 109        $part = trim($part);
 110        $part = trim($part, '"+');
 111        if (!strlen($part)) {
 112          continue;
 113        }
 114  
 115        $matches = null;
 116        $has_matches = preg_match_all(
 117          '/(?:^|\b)('.preg_quote($part, '/').')/i',
 118          $str,
 119          $matches,
 120          PREG_OFFSET_CAPTURE);
 121  
 122        if (!$has_matches) {
 123          continue;
 124        }
 125  
 126        // Flag the matching part of the range for boldening.
 127        foreach ($matches[1] as $match) {
 128          $offset = $match[1];
 129          for ($ii = 0; $ii < strlen($match[0]); $ii++) {
 130            $bold[$offset + $ii] = true;
 131          }
 132        }
 133      }
 134  
 135      // Split the string into ranges, applying bold styling as required.
 136      $out = array();
 137      $buf = '';
 138      $pos = 0;
 139      $is_bold = false;
 140      foreach (phutil_utf8v($str) as $chr) {
 141        if ($bold[$pos] != $is_bold) {
 142          if (strlen($buf)) {
 143            if ($is_bold) {
 144              $out[] = phutil_tag('strong', array(), $buf);
 145            } else {
 146              $out[] = $buf;
 147            }
 148            $buf = '';
 149          }
 150          $is_bold = !$is_bold;
 151        }
 152        $buf .= $chr;
 153        $pos += strlen($chr);
 154      }
 155  
 156      if (strlen($buf)) {
 157        if ($is_bold) {
 158          $out[] = phutil_tag('strong', array(), $buf);
 159        } else {
 160          $out[] = $buf;
 161        }
 162      }
 163  
 164      return $out;
 165    }
 166  
 167  }


Generated: Sun Nov 30 09:20:46 2014 Cross-referenced by PHPXref 0.7.1