[ Index ]

PHP Cross Reference of MediaWiki-1.24.0

title

Body

[close]

/includes/pager/ -> IndexPager.php (source)

   1  <?php
   2  /**
   3   * Efficient paging for SQL queries.
   4   *
   5   * This program is free software; you can redistribute it and/or modify
   6   * it under the terms of the GNU General Public License as published by
   7   * the Free Software Foundation; either version 2 of the License, or
   8   * (at your option) any later version.
   9   *
  10   * This program is distributed in the hope that it will be useful,
  11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13   * GNU General Public License for more details.
  14   *
  15   * You should have received a copy of the GNU General Public License along
  16   * with this program; if not, write to the Free Software Foundation, Inc.,
  17   * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
  18   * http://www.gnu.org/copyleft/gpl.html
  19   *
  20   * @file
  21   * @ingroup Pager
  22   */
  23  
  24  /**
  25   * IndexPager is an efficient pager which uses a (roughly unique) index in the
  26   * data set to implement paging, rather than a "LIMIT offset,limit" clause.
  27   * In MySQL, such a limit/offset clause requires counting through the
  28   * specified number of offset rows to find the desired data, which can be
  29   * expensive for large offsets.
  30   *
  31   * ReverseChronologicalPager is a child class of the abstract IndexPager, and
  32   * contains  some formatting and display code which is specific to the use of
  33   * timestamps as  indexes. Here is a synopsis of its operation:
  34   *
  35   *    * The query is specified by the offset, limit and direction (dir)
  36   *      parameters, in addition to any subclass-specific parameters.
  37   *    * The offset is the non-inclusive start of the DB query. A row with an
  38   *      index value equal to the offset will never be shown.
  39   *    * The query may either be done backwards, where the rows are returned by
  40   *      the database in the opposite order to which they are displayed to the
  41   *      user, or forwards. This is specified by the "dir" parameter, dir=prev
  42   *      means backwards, anything else means forwards. The offset value
  43   *      specifies the start of the database result set, which may be either
  44   *      the start or end of the displayed data set. This allows "previous"
  45   *      links to be implemented without knowledge of the index value at the
  46   *      start of the previous page.
  47   *    * An additional row beyond the user-specified limit is always requested.
  48   *      This allows us to tell whether we should display a "next" link in the
  49   *      case of forwards mode, or a "previous" link in the case of backwards
  50   *      mode. Determining whether to display the other link (the one for the
  51   *      page before the start of the database result set) can be done
  52   *      heuristically by examining the offset.
  53   *
  54   *    * An empty offset indicates that the offset condition should be omitted
  55   *      from the query. This naturally produces either the first page or the
  56   *      last page depending on the dir parameter.
  57   *
  58   *  Subclassing the pager to implement concrete functionality should be fairly
  59   *  simple, please see the examples in HistoryAction.php and
  60   *  SpecialBlockList.php. You just need to override formatRow(),
  61   *  getQueryInfo() and getIndexField(). Don't forget to call the parent
  62   *  constructor if you override it.
  63   *
  64   * @ingroup Pager
  65   */
  66  abstract class IndexPager extends ContextSource implements Pager {
  67      /**
  68       * Constants for the $mDefaultDirection field.
  69       *
  70       * These are boolean for historical reasons and should stay boolean for backwards-compatibility.
  71       */
  72      const DIR_ASCENDING = false;
  73      const DIR_DESCENDING = true;
  74  
  75      public $mRequest;
  76      public $mLimitsShown = array( 20, 50, 100, 250, 500 );
  77      public $mDefaultLimit = 50;
  78      public $mOffset, $mLimit;
  79      public $mQueryDone = false;
  80      public $mDb;
  81      public $mPastTheEndRow;
  82  
  83      /**
  84       * The index to actually be used for ordering. This is a single column,
  85       * for one ordering, even if multiple orderings are supported.
  86       */
  87      protected $mIndexField;
  88      /**
  89       * An array of secondary columns to order by. These fields are not part of the offset.
  90       * This is a column list for one ordering, even if multiple orderings are supported.
  91       */
  92      protected $mExtraSortFields;
  93      /** For pages that support multiple types of ordering, which one to use.
  94       */
  95      protected $mOrderType;
  96      /**
  97       * $mDefaultDirection gives the direction to use when sorting results:
  98       * DIR_ASCENDING or DIR_DESCENDING.  If $mIsBackwards is set, we
  99       * start from the opposite end, but we still sort the page itself according
 100       * to $mDefaultDirection.  E.g., if $mDefaultDirection is false but we're
 101       * going backwards, we'll display the last page of results, but the last
 102       * result will be at the bottom, not the top.
 103       *
 104       * Like $mIndexField, $mDefaultDirection will be a single value even if the
 105       * class supports multiple default directions for different order types.
 106       */
 107      public $mDefaultDirection;
 108      public $mIsBackwards;
 109  
 110      /** True if the current result set is the first one */
 111      public $mIsFirst;
 112      public $mIsLast;
 113  
 114      protected $mLastShown, $mFirstShown, $mPastTheEndIndex, $mDefaultQuery, $mNavigationBar;
 115  
 116      /**
 117       * Whether to include the offset in the query
 118       */
 119      protected $mIncludeOffset = false;
 120  
 121      /**
 122       * Result object for the query. Warning: seek before use.
 123       *
 124       * @var ResultWrapper
 125       */
 126      public $mResult;
 127  
 128  	public function __construct( IContextSource $context = null ) {
 129          if ( $context ) {
 130              $this->setContext( $context );
 131          }
 132  
 133          $this->mRequest = $this->getRequest();
 134  
 135          # NB: the offset is quoted, not validated. It is treated as an
 136          # arbitrary string to support the widest variety of index types. Be
 137          # careful outputting it into HTML!
 138          $this->mOffset = $this->mRequest->getText( 'offset' );
 139  
 140          # Use consistent behavior for the limit options
 141          $this->mDefaultLimit = $this->getUser()->getIntOption( 'rclimit' );
 142          if ( !$this->mLimit ) {
 143              // Don't override if a subclass calls $this->setLimit() in its constructor.
 144              list( $this->mLimit, /* $offset */ ) = $this->mRequest->getLimitOffset();
 145          }
 146  
 147          $this->mIsBackwards = ( $this->mRequest->getVal( 'dir' ) == 'prev' );
 148          # Let the subclass set the DB here; otherwise use a slave DB for the current wiki
 149          $this->mDb = $this->mDb ?: wfGetDB( DB_SLAVE );
 150  
 151          $index = $this->getIndexField(); // column to sort on
 152          $extraSort = $this->getExtraSortFields(); // extra columns to sort on for query planning
 153          $order = $this->mRequest->getVal( 'order' );
 154          if ( is_array( $index ) && isset( $index[$order] ) ) {
 155              $this->mOrderType = $order;
 156              $this->mIndexField = $index[$order];
 157              $this->mExtraSortFields = isset( $extraSort[$order] )
 158                  ? (array)$extraSort[$order]
 159                  : array();
 160          } elseif ( is_array( $index ) ) {
 161              # First element is the default
 162              reset( $index );
 163              list( $this->mOrderType, $this->mIndexField ) = each( $index );
 164              $this->mExtraSortFields = isset( $extraSort[$this->mOrderType] )
 165                  ? (array)$extraSort[$this->mOrderType]
 166                  : array();
 167          } else {
 168              # $index is not an array
 169              $this->mOrderType = null;
 170              $this->mIndexField = $index;
 171              $this->mExtraSortFields = (array)$extraSort;
 172          }
 173  
 174          if ( !isset( $this->mDefaultDirection ) ) {
 175              $dir = $this->getDefaultDirections();
 176              $this->mDefaultDirection = is_array( $dir )
 177                  ? $dir[$this->mOrderType]
 178                  : $dir;
 179          }
 180      }
 181  
 182      /**
 183       * Get the Database object in use
 184       *
 185       * @return DatabaseBase
 186       */
 187  	public function getDatabase() {
 188          return $this->mDb;
 189      }
 190  
 191      /**
 192       * Do the query, using information from the object context. This function
 193       * has been kept minimal to make it overridable if necessary, to allow for
 194       * result sets formed from multiple DB queries.
 195       */
 196  	public function doQuery() {
 197          # Use the child class name for profiling
 198          $fname = __METHOD__ . ' (' . get_class( $this ) . ')';
 199          wfProfileIn( $fname );
 200  
 201          // @todo This should probably compare to DIR_DESCENDING and DIR_ASCENDING constants
 202          $descending = ( $this->mIsBackwards == $this->mDefaultDirection );
 203          # Plus an extra row so that we can tell the "next" link should be shown
 204          $queryLimit = $this->mLimit + 1;
 205  
 206          if ( $this->mOffset == '' ) {
 207              $isFirst = true;
 208          } else {
 209              // If there's an offset, we may or may not be at the first entry.
 210              // The only way to tell is to run the query in the opposite
 211              // direction see if we get a row.
 212              $oldIncludeOffset = $this->mIncludeOffset;
 213              $this->mIncludeOffset = !$this->mIncludeOffset;
 214              $isFirst = !$this->reallyDoQuery( $this->mOffset, 1, !$descending )->numRows();
 215              $this->mIncludeOffset = $oldIncludeOffset;
 216          }
 217  
 218          $this->mResult = $this->reallyDoQuery(
 219              $this->mOffset,
 220              $queryLimit,
 221              $descending
 222          );
 223  
 224          $this->extractResultInfo( $isFirst, $queryLimit, $this->mResult );
 225          $this->mQueryDone = true;
 226  
 227          $this->preprocessResults( $this->mResult );
 228          $this->mResult->rewind(); // Paranoia
 229  
 230          wfProfileOut( $fname );
 231      }
 232  
 233      /**
 234       * @return ResultWrapper The result wrapper.
 235       */
 236  	function getResult() {
 237          return $this->mResult;
 238      }
 239  
 240      /**
 241       * Set the offset from an other source than the request
 242       *
 243       * @param int|string $offset
 244       */
 245  	function setOffset( $offset ) {
 246          $this->mOffset = $offset;
 247      }
 248  
 249      /**
 250       * Set the limit from an other source than the request
 251       *
 252       * Verifies limit is between 1 and 5000
 253       *
 254       * @param int|string $limit
 255       */
 256  	function setLimit( $limit ) {
 257          $limit = (int)$limit;
 258          // WebRequest::getLimitOffset() puts a cap of 5000, so do same here.
 259          if ( $limit > 5000 ) {
 260              $limit = 5000;
 261          }
 262          if ( $limit > 0 ) {
 263              $this->mLimit = $limit;
 264          }
 265      }
 266  
 267      /**
 268       * Get the current limit
 269       *
 270       * @return int
 271       */
 272  	function getLimit() {
 273          return $this->mLimit;
 274      }
 275  
 276      /**
 277       * Set whether a row matching exactly the offset should be also included
 278       * in the result or not. By default this is not the case, but when the
 279       * offset is user-supplied this might be wanted.
 280       *
 281       * @param bool $include
 282       */
 283  	public function setIncludeOffset( $include ) {
 284          $this->mIncludeOffset = $include;
 285      }
 286  
 287      /**
 288       * Extract some useful data from the result object for use by
 289       * the navigation bar, put it into $this
 290       *
 291       * @param bool $isFirst False if there are rows before those fetched (i.e.
 292       *     if a "previous" link would make sense)
 293       * @param int $limit Exact query limit
 294       * @param ResultWrapper $res
 295       */
 296  	function extractResultInfo( $isFirst, $limit, ResultWrapper $res ) {
 297          $numRows = $res->numRows();
 298          if ( $numRows ) {
 299              # Remove any table prefix from index field
 300              $parts = explode( '.', $this->mIndexField );
 301              $indexColumn = end( $parts );
 302  
 303              $row = $res->fetchRow();
 304              $firstIndex = $row[$indexColumn];
 305  
 306              # Discard the extra result row if there is one
 307              if ( $numRows > $this->mLimit && $numRows > 1 ) {
 308                  $res->seek( $numRows - 1 );
 309                  $this->mPastTheEndRow = $res->fetchObject();
 310                  $this->mPastTheEndIndex = $this->mPastTheEndRow->$indexColumn;
 311                  $res->seek( $numRows - 2 );
 312                  $row = $res->fetchRow();
 313                  $lastIndex = $row[$indexColumn];
 314              } else {
 315                  $this->mPastTheEndRow = null;
 316                  # Setting indexes to an empty string means that they will be
 317                  # omitted if they would otherwise appear in URLs. It just so
 318                  # happens that this  is the right thing to do in the standard
 319                  # UI, in all the relevant cases.
 320                  $this->mPastTheEndIndex = '';
 321                  $res->seek( $numRows - 1 );
 322                  $row = $res->fetchRow();
 323                  $lastIndex = $row[$indexColumn];
 324              }
 325          } else {
 326              $firstIndex = '';
 327              $lastIndex = '';
 328              $this->mPastTheEndRow = null;
 329              $this->mPastTheEndIndex = '';
 330          }
 331  
 332          if ( $this->mIsBackwards ) {
 333              $this->mIsFirst = ( $numRows < $limit );
 334              $this->mIsLast = $isFirst;
 335              $this->mLastShown = $firstIndex;
 336              $this->mFirstShown = $lastIndex;
 337          } else {
 338              $this->mIsFirst = $isFirst;
 339              $this->mIsLast = ( $numRows < $limit );
 340              $this->mLastShown = $lastIndex;
 341              $this->mFirstShown = $firstIndex;
 342          }
 343      }
 344  
 345      /**
 346       * Get some text to go in brackets in the "function name" part of the SQL comment
 347       *
 348       * @return string
 349       */
 350  	function getSqlComment() {
 351          return get_class( $this );
 352      }
 353  
 354      /**
 355       * Do a query with specified parameters, rather than using the object
 356       * context
 357       *
 358       * @param string $offset Index offset, inclusive
 359       * @param int $limit Exact query limit
 360       * @param bool $descending Query direction, false for ascending, true for descending
 361       * @return ResultWrapper
 362       */
 363  	public function reallyDoQuery( $offset, $limit, $descending ) {
 364          list( $tables, $fields, $conds, $fname, $options, $join_conds ) =
 365              $this->buildQueryInfo( $offset, $limit, $descending );
 366  
 367          return $this->mDb->select( $tables, $fields, $conds, $fname, $options, $join_conds );
 368      }
 369  
 370      /**
 371       * Build variables to use by the database wrapper.
 372       *
 373       * @param string $offset Index offset, inclusive
 374       * @param int $limit Exact query limit
 375       * @param bool $descending Query direction, false for ascending, true for descending
 376       * @return array
 377       */
 378  	protected function buildQueryInfo( $offset, $limit, $descending ) {
 379          $fname = __METHOD__ . ' (' . $this->getSqlComment() . ')';
 380          $info = $this->getQueryInfo();
 381          $tables = $info['tables'];
 382          $fields = $info['fields'];
 383          $conds = isset( $info['conds'] ) ? $info['conds'] : array();
 384          $options = isset( $info['options'] ) ? $info['options'] : array();
 385          $join_conds = isset( $info['join_conds'] ) ? $info['join_conds'] : array();
 386          $sortColumns = array_merge( array( $this->mIndexField ), $this->mExtraSortFields );
 387          if ( $descending ) {
 388              $options['ORDER BY'] = $sortColumns;
 389              $operator = $this->mIncludeOffset ? '>=' : '>';
 390          } else {
 391              $orderBy = array();
 392              foreach ( $sortColumns as $col ) {
 393                  $orderBy[] = $col . ' DESC';
 394              }
 395              $options['ORDER BY'] = $orderBy;
 396              $operator = $this->mIncludeOffset ? '<=' : '<';
 397          }
 398          if ( $offset != '' ) {
 399              $conds[] = $this->mIndexField . $operator . $this->mDb->addQuotes( $offset );
 400          }
 401          $options['LIMIT'] = intval( $limit );
 402          return array( $tables, $fields, $conds, $fname, $options, $join_conds );
 403      }
 404  
 405      /**
 406       * Pre-process results; useful for performing batch existence checks, etc.
 407       *
 408       * @param ResultWrapper $result
 409       */
 410  	protected function preprocessResults( $result ) {
 411      }
 412  
 413      /**
 414       * Get the formatted result list. Calls getStartBody(), formatRow() and
 415       * getEndBody(), concatenates the results and returns them.
 416       *
 417       * @return string
 418       */
 419  	public function getBody() {
 420          if ( !$this->mQueryDone ) {
 421              $this->doQuery();
 422          }
 423  
 424          if ( $this->mResult->numRows() ) {
 425              # Do any special query batches before display
 426              $this->doBatchLookups();
 427          }
 428  
 429          # Don't use any extra rows returned by the query
 430          $numRows = min( $this->mResult->numRows(), $this->mLimit );
 431  
 432          $s = $this->getStartBody();
 433          if ( $numRows ) {
 434              if ( $this->mIsBackwards ) {
 435                  for ( $i = $numRows - 1; $i >= 0; $i-- ) {
 436                      $this->mResult->seek( $i );
 437                      $row = $this->mResult->fetchObject();
 438                      $s .= $this->formatRow( $row );
 439                  }
 440              } else {
 441                  $this->mResult->seek( 0 );
 442                  for ( $i = 0; $i < $numRows; $i++ ) {
 443                      $row = $this->mResult->fetchObject();
 444                      $s .= $this->formatRow( $row );
 445                  }
 446              }
 447          } else {
 448              $s .= $this->getEmptyBody();
 449          }
 450          $s .= $this->getEndBody();
 451          return $s;
 452      }
 453  
 454      /**
 455       * Make a self-link
 456       *
 457       * @param string $text Text displayed on the link
 458       * @param array $query Associative array of parameter to be in the query string
 459       * @param string $type Link type used to create additional attributes, like "rel", "class" or
 460       *  "title". Valid values (non-exhaustive list): 'first', 'last', 'prev', 'next', 'asc', 'desc'.
 461       * @return string HTML fragment
 462       */
 463  	function makeLink( $text, array $query = null, $type = null ) {
 464          if ( $query === null ) {
 465              return $text;
 466          }
 467  
 468          $attrs = array();
 469          if ( in_array( $type, array( 'prev', 'next' ) ) ) {
 470              $attrs['rel'] = $type;
 471          }
 472  
 473          if ( in_array( $type, array( 'asc', 'desc' ) ) ) {
 474              $attrs['title'] = wfMessage( $type == 'asc' ? 'sort-ascending' : 'sort-descending' )->text();
 475          }
 476  
 477          if ( $type ) {
 478              $attrs['class'] = "mw-{$type}link";
 479          }
 480  
 481  
 482          return Linker::linkKnown(
 483              $this->getTitle(),
 484              $text,
 485              $attrs,
 486              $query + $this->getDefaultQuery()
 487          );
 488      }
 489  
 490      /**
 491       * Called from getBody(), before getStartBody() is called and
 492       * after doQuery() was called. This will be called only if there
 493       * are rows in the result set.
 494       *
 495       * @return void
 496       */
 497  	protected function doBatchLookups() {
 498      }
 499  
 500      /**
 501       * Hook into getBody(), allows text to be inserted at the start. This
 502       * will be called even if there are no rows in the result set.
 503       *
 504       * @return string
 505       */
 506  	protected function getStartBody() {
 507          return '';
 508      }
 509  
 510      /**
 511       * Hook into getBody() for the end of the list
 512       *
 513       * @return string
 514       */
 515  	protected function getEndBody() {
 516          return '';
 517      }
 518  
 519      /**
 520       * Hook into getBody(), for the bit between the start and the
 521       * end when there are no rows
 522       *
 523       * @return string
 524       */
 525  	protected function getEmptyBody() {
 526          return '';
 527      }
 528  
 529      /**
 530       * Get an array of query parameters that should be put into self-links.
 531       * By default, all parameters passed in the URL are used, except for a
 532       * short blacklist.
 533       *
 534       * @return array Associative array
 535       */
 536  	function getDefaultQuery() {
 537          if ( !isset( $this->mDefaultQuery ) ) {
 538              $this->mDefaultQuery = $this->getRequest()->getQueryValues();
 539              unset( $this->mDefaultQuery['title'] );
 540              unset( $this->mDefaultQuery['dir'] );
 541              unset( $this->mDefaultQuery['offset'] );
 542              unset( $this->mDefaultQuery['limit'] );
 543              unset( $this->mDefaultQuery['order'] );
 544              unset( $this->mDefaultQuery['month'] );
 545              unset( $this->mDefaultQuery['year'] );
 546          }
 547          return $this->mDefaultQuery;
 548      }
 549  
 550      /**
 551       * Get the number of rows in the result set
 552       *
 553       * @return int
 554       */
 555  	function getNumRows() {
 556          if ( !$this->mQueryDone ) {
 557              $this->doQuery();
 558          }
 559          return $this->mResult->numRows();
 560      }
 561  
 562      /**
 563       * Get a URL query array for the prev, next, first and last links.
 564       *
 565       * @return array
 566       */
 567  	function getPagingQueries() {
 568          if ( !$this->mQueryDone ) {
 569              $this->doQuery();
 570          }
 571  
 572          # Don't announce the limit everywhere if it's the default
 573          $urlLimit = $this->mLimit == $this->mDefaultLimit ? null : $this->mLimit;
 574  
 575          if ( $this->mIsFirst ) {
 576              $prev = false;
 577              $first = false;
 578          } else {
 579              $prev = array(
 580                  'dir' => 'prev',
 581                  'offset' => $this->mFirstShown,
 582                  'limit' => $urlLimit
 583              );
 584              $first = array( 'limit' => $urlLimit );
 585          }
 586          if ( $this->mIsLast ) {
 587              $next = false;
 588              $last = false;
 589          } else {
 590              $next = array( 'offset' => $this->mLastShown, 'limit' => $urlLimit );
 591              $last = array( 'dir' => 'prev', 'limit' => $urlLimit );
 592          }
 593          return array(
 594              'prev' => $prev,
 595              'next' => $next,
 596              'first' => $first,
 597              'last' => $last
 598          );
 599      }
 600  
 601      /**
 602       * Returns whether to show the "navigation bar"
 603       *
 604       * @return bool
 605       */
 606  	function isNavigationBarShown() {
 607          if ( !$this->mQueryDone ) {
 608              $this->doQuery();
 609          }
 610          // Hide navigation by default if there is nothing to page
 611          return !( $this->mIsFirst && $this->mIsLast );
 612      }
 613  
 614      /**
 615       * Get paging links. If a link is disabled, the item from $disabledTexts
 616       * will be used. If there is no such item, the unlinked text from
 617       * $linkTexts will be used. Both $linkTexts and $disabledTexts are arrays
 618       * of HTML.
 619       *
 620       * @param array $linkTexts
 621       * @param array $disabledTexts
 622       * @return array
 623       */
 624  	function getPagingLinks( $linkTexts, $disabledTexts = array() ) {
 625          $queries = $this->getPagingQueries();
 626          $links = array();
 627  
 628          foreach ( $queries as $type => $query ) {
 629              if ( $query !== false ) {
 630                  $links[$type] = $this->makeLink(
 631                      $linkTexts[$type],
 632                      $queries[$type],
 633                      $type
 634                  );
 635              } elseif ( isset( $disabledTexts[$type] ) ) {
 636                  $links[$type] = $disabledTexts[$type];
 637              } else {
 638                  $links[$type] = $linkTexts[$type];
 639              }
 640          }
 641  
 642          return $links;
 643      }
 644  
 645  	function getLimitLinks() {
 646          $links = array();
 647          if ( $this->mIsBackwards ) {
 648              $offset = $this->mPastTheEndIndex;
 649          } else {
 650              $offset = $this->mOffset;
 651          }
 652          foreach ( $this->mLimitsShown as $limit ) {
 653              $links[] = $this->makeLink(
 654                  $this->getLanguage()->formatNum( $limit ),
 655                  array( 'offset' => $offset, 'limit' => $limit ),
 656                  'num'
 657              );
 658          }
 659          return $links;
 660      }
 661  
 662      /**
 663       * Abstract formatting function. This should return an HTML string
 664       * representing the result row $row. Rows will be concatenated and
 665       * returned by getBody()
 666       *
 667       * @param array|stdClass $row Database row
 668       * @return string
 669       */
 670      abstract function formatRow( $row );
 671  
 672      /**
 673       * This function should be overridden to provide all parameters
 674       * needed for the main paged query. It returns an associative
 675       * array with the following elements:
 676       *    tables => Table(s) for passing to Database::select()
 677       *    fields => Field(s) for passing to Database::select(), may be *
 678       *    conds => WHERE conditions
 679       *    options => option array
 680       *    join_conds => JOIN conditions
 681       *
 682       * @return array
 683       */
 684      abstract function getQueryInfo();
 685  
 686      /**
 687       * This function should be overridden to return the name of the index fi-
 688       * eld.  If the pager supports multiple orders, it may return an array of
 689       * 'querykey' => 'indexfield' pairs, so that a request with &count=querykey
 690       * will use indexfield to sort.  In this case, the first returned key is
 691       * the default.
 692       *
 693       * Needless to say, it's really not a good idea to use a non-unique index
 694       * for this!  That won't page right.
 695       *
 696       * @return string|array
 697       */
 698      abstract function getIndexField();
 699  
 700      /**
 701       * This function should be overridden to return the names of secondary columns
 702       * to order by in addition to the column in getIndexField(). These fields will
 703       * not be used in the pager offset or in any links for users.
 704       *
 705       * If getIndexField() returns an array of 'querykey' => 'indexfield' pairs then
 706       * this must return a corresponding array of 'querykey' => array( fields...) pairs
 707       * in order for a request with &count=querykey to use array( fields...) to sort.
 708       *
 709       * This is useful for pagers that GROUP BY a unique column (say page_id)
 710       * and ORDER BY another (say page_len). Using GROUP BY and ORDER BY both on
 711       * page_len,page_id avoids temp tables (given a page_len index). This would
 712       * also work if page_id was non-unique but we had a page_len,page_id index.
 713       *
 714       * @return array
 715       */
 716  	protected function getExtraSortFields() {
 717          return array();
 718      }
 719  
 720      /**
 721       * Return the default sorting direction: DIR_ASCENDING or DIR_DESCENDING.
 722       * You can also have an associative array of ordertype => dir,
 723       * if multiple order types are supported.  In this case getIndexField()
 724       * must return an array, and the keys of that must exactly match the keys
 725       * of this.
 726       *
 727       * For backward compatibility, this method's return value will be ignored
 728       * if $this->mDefaultDirection is already set when the constructor is
 729       * called, for instance if it's statically initialized.  In that case the
 730       * value of that variable (which must be a boolean) will be used.
 731       *
 732       * Note that despite its name, this does not return the value of the
 733       * $this->mDefaultDirection member variable.  That's the default for this
 734       * particular instantiation, which is a single value.  This is the set of
 735       * all defaults for the class.
 736       *
 737       * @return bool
 738       */
 739  	protected function getDefaultDirections() {
 740          return IndexPager::DIR_ASCENDING;
 741      }
 742  }


Generated: Fri Nov 28 14:03:12 2014 Cross-referenced by PHPXref 0.7.1