public function execute()
 {
     $ref_table = new PhabricatorFeedStoryReference();
     $story_table = new PhabricatorFeedStoryData();
     $conn = $story_table->establishConnection('r');
     $where = array();
     if ($this->filterPHIDs) {
         $where[] = qsprintf($conn, 'ref.objectPHID IN (%Ls)', $this->filterPHIDs);
     }
     // For "before" queries, we can just add a constraint to the WHERE clause.
     // For "after" queries, we must also reverse the result ordering, since
     // otherwise we'll always grab the first page of results if there's a limit.
     // After MySQL applies the limit, we reverse the page in PHP (below) to
     // ensure consistent ordering.
     $order = 'DESC';
     if ($this->after) {
         $where[] = qsprintf($conn, 'ref.chronologicalKey > %s', $this->after);
         $order = 'ASC';
     }
     if ($this->before) {
         $where[] = qsprintf($conn, 'ref.chronologicalKey < %s', $this->before);
     }
     if ($where) {
         $where = 'WHERE (' . implode(') AND (', $where) . ')';
     } else {
         $where = '';
     }
     $data = queryfx_all($conn, 'SELECT story.* FROM %T ref
     JOIN %T story ON ref.chronologicalKey = story.chronologicalKey
     %Q
     GROUP BY ref.chronologicalKey
     ORDER BY ref.chronologicalKey %Q
     LIMIT %d', $ref_table->getTableName(), $story_table->getTableName(), $where, $order, $this->limit);
     if ($order != 'DESC') {
         // If we did order ASC to pull 'after' data, reverse the result set so
         // that stories are returned in a consistent (descending) order.
         $data = array_reverse($data);
     }
     $data = $story_table->loadAllFromArray($data);
     $stories = array();
     foreach ($data as $story_data) {
         $class = $story_data->getStoryType();
         try {
             if (!class_exists($class) || !is_subclass_of($class, 'PhabricatorFeedStory')) {
                 $class = 'PhabricatorFeedStoryUnknown';
             }
         } catch (PhutilMissingSymbolException $ex) {
             // If the class can't be loaded, libphutil will throw an exception.
             // Render the story using the unknown story view.
             $class = 'PhabricatorFeedStoryUnknown';
         }
         $stories[] = newv($class, array($story_data));
     }
     return $stories;
 }
 public function execute()
 {
     $ref_table = new PhabricatorFeedStoryReference();
     $story_table = new PhabricatorFeedStoryData();
     $conn = $story_table->establishConnection('r');
     $where = array();
     if ($this->filterPHIDs) {
         $where[] = qsprintf($conn, 'ref.objectPHID IN (%Ls)', $this->filterPHIDs);
     }
     if ($where) {
         $where = 'WHERE (' . implode(') AND (', $where) . ')';
     } else {
         $where = '';
     }
     $data = queryfx_all($conn, 'SELECT story.* FROM %T ref
     JOIN %T story ON ref.chronologicalKey = story.chronologicalKey
     %Q
     GROUP BY story.chronologicalKey
     ORDER BY story.chronologicalKey DESC
     LIMIT %d', $ref_table->getTableName(), $story_table->getTableName(), $where, $this->limit);
     $data = $story_table->loadAllFromArray($data);
     $stories = array();
     foreach ($data as $story_data) {
         $class = $story_data->getStoryType();
         try {
             if (!class_exists($class) || !is_subclass_of($class, 'PhabricatorFeedStory')) {
                 $class = 'PhabricatorFeedStoryUnknown';
             }
         } catch (PhutilMissingSymbolException $ex) {
             // If the class can't be loaded, libphutil will throw an exception.
             // Render the story using the unknown story view.
             $class = 'PhabricatorFeedStoryUnknown';
         }
         $stories[] = newv($class, array($story_data));
     }
     return $stories;
 }