368 lines
8.7 KiB
PHP
368 lines
8.7 KiB
PHP
<?php
|
|
/**
|
|
* A helper class to query the globalimagelinks table
|
|
*
|
|
*/
|
|
class GlobalUsageQuery {
|
|
private $limit = 50;
|
|
private $offset;
|
|
private $hasMore = false;
|
|
private $filterLocal = false;
|
|
private $result;
|
|
private $continue;
|
|
private $reversed = false;
|
|
private $target = null;
|
|
|
|
/**
|
|
* @param $target mixed Title or db key, or array of db keys of target(s)
|
|
*/
|
|
public function __construct( $target ) {
|
|
global $wgGlobalDatabase;
|
|
$this->db = wfGetDB( DB_SLAVE, array(), $wgGlobalDatabase );
|
|
if ( $target instanceof Title && $target->getNamespace( ) == NS_FILE ) {
|
|
$this->target = $target->getDBKey();
|
|
} else {
|
|
$this->target = $target;
|
|
}
|
|
$this->offset = array();
|
|
|
|
}
|
|
|
|
/**
|
|
* Set the offset parameter
|
|
*
|
|
* @param $offset string offset
|
|
* @param $reversed bool True if this is the upper offset
|
|
*/
|
|
public function setOffset( $offset, $reversed = null ) {
|
|
if ( !is_null( $reversed ) ) {
|
|
$this->reversed = $reversed;
|
|
}
|
|
|
|
if ( !is_array( $offset ) ) {
|
|
$offset = explode( '|', $offset );
|
|
}
|
|
|
|
if ( count( $offset ) == 3 ) {
|
|
$this->offset = $offset;
|
|
return true;
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
/**
|
|
* Return the offset set by the user
|
|
*
|
|
* @return array offset
|
|
*/
|
|
public function getOffsetString() {
|
|
return implode( '|', $this->offset );
|
|
}
|
|
/**
|
|
* Is the result reversed
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function isReversed() {
|
|
return $this->reversed;
|
|
}
|
|
|
|
/**
|
|
* Returns the string used for continuation in a file search
|
|
*
|
|
* @return string
|
|
*
|
|
*/
|
|
public function getContinueFileString() {
|
|
if ( $this->hasMore() ) {
|
|
return "{$this->lastRow->gil_to}|{$this->lastRow->gil_wiki}|{$this->lastRow->gil_page}";
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the string used for continuation in a template search
|
|
*
|
|
* @return string
|
|
*
|
|
*/
|
|
public function getContinueTemplateString() {
|
|
if ( $this->hasMore() ) {
|
|
return "{$this->lastRow->gtl_to_title}|{$this->lastRow->gtl_from_wiki}|{$this->lastRow->gtl_from_page}";
|
|
} else {
|
|
return '';
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Set the maximum amount of items to return. Capped at 500.
|
|
*
|
|
* @param $limit int The limit
|
|
*/
|
|
public function setLimit( $limit ) {
|
|
$this->limit = min( $limit, 500 );
|
|
}
|
|
/**
|
|
* Returns the user set limit
|
|
*/
|
|
public function getLimit() {
|
|
return $this->limit;
|
|
}
|
|
|
|
/**
|
|
* Set whether to filter out the local usage
|
|
*/
|
|
public function filterLocal( $value = true ) {
|
|
$this->filterLocal = $value;
|
|
}
|
|
|
|
/**
|
|
* Executes the query for a file search
|
|
*/
|
|
public function searchTemplate() {
|
|
global $wgLocalInterwiki;
|
|
|
|
/* Construct a where clause */
|
|
// Add target template(s)
|
|
$where = array( 'gtl_to_prefix' => $wgLocalInterwiki,
|
|
'gtl_to_namespace' => $this->target->getNamespace( ),
|
|
'gtl_to_title' => $this->target->getDBkey( )
|
|
);
|
|
|
|
// Set the continuation condition
|
|
$order = 'ASC';
|
|
if ( $this->offset ) {
|
|
$qTo = $this->db->addQuotes( $this->offset[0] );
|
|
$qWiki = $this->db->addQuotes( $this->offset[1] );
|
|
$qPage = intval( $this->offset[2] );
|
|
|
|
// Check which limit we got in order to determine which way to traverse rows
|
|
if ( $this->reversed ) {
|
|
// Reversed traversal; do not include offset row
|
|
$op1 = '<';
|
|
$op2 = '<';
|
|
$order = 'DESC';
|
|
} else {
|
|
// Normal traversal; include offset row
|
|
$op1 = '>';
|
|
$op2 = '>=';
|
|
$order = 'ASC';
|
|
}
|
|
|
|
$where[] = "(gtl_to_title $op1 $qTo) OR " .
|
|
"(gtl_to_title = $qTo AND gtl_from_wiki $op1 $qWiki) OR " .
|
|
"(gtl_to_title = $qTo AND gtl_from_wiki = $qWiki AND gtl_from_page $op2 $qPage)";
|
|
}
|
|
|
|
/* Perform select (Duh.) */
|
|
$res = $this->db->select(
|
|
array(
|
|
'globaltemplatelinks',
|
|
'globalnamespaces'
|
|
),
|
|
array(
|
|
'gtl_to_title',
|
|
'gtl_from_wiki',
|
|
'gtl_from_page',
|
|
'gtl_from_namespace',
|
|
'gtl_from_title'
|
|
),
|
|
$where,
|
|
__METHOD__,
|
|
array(
|
|
'ORDER BY' => "gtl_to_title $order, gtl_from_wiki $order, gtl_from_page $order",
|
|
// Select an extra row to check whether we have more rows available
|
|
'LIMIT' => $this->limit + 1,
|
|
),
|
|
array(
|
|
'gtl_from_namespace = gn_namespace'
|
|
)
|
|
);
|
|
|
|
/* Process result */
|
|
// Always return the result in the same order; regardless whether reversed was specified
|
|
// reversed is really only used to determine from which direction the offset is
|
|
$rows = array();
|
|
foreach ( $res as $row ) {
|
|
$rows[] = $row;
|
|
}
|
|
if ( $this->reversed ) {
|
|
$rows = array_reverse( $rows );
|
|
}
|
|
|
|
// Build the result array
|
|
$count = 0;
|
|
$this->hasMore = false;
|
|
$this->result = array();
|
|
foreach ( $rows as $row ) {
|
|
$count++;
|
|
if ( $count > $this->limit ) {
|
|
// We've reached the extra row that indicates that there are more rows
|
|
$this->hasMore = true;
|
|
$this->lastRow = $row;
|
|
break;
|
|
}
|
|
|
|
if ( !isset( $this->result[$row->gtl_to_title] ) ) {
|
|
$this->result[$row->gtl_to_title] = array();
|
|
}
|
|
if ( !isset( $this->result[$row->gtl_to_title][$row->gtl_from_wiki] ) ) {
|
|
$this->result[$row->gtl_to_title][$row->gtl_from_wiki] = array();
|
|
}
|
|
|
|
$this->result[$row->gtl_to_title][$row->gtl_from_wiki][] = array(
|
|
'template' => $row->gtl_to_title,
|
|
'id' => $row->gtl_from_page,
|
|
'namespace' => $row->gn_namespacetext,
|
|
'title' => $row->gtl_from_title,
|
|
'wiki' => $row->gtl_from_wiki,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Executes the query for a template search
|
|
*/
|
|
public function searchFile() {
|
|
/* Construct a where clause */
|
|
// Add target image(s)
|
|
$where = array( 'gil_to' => $this->target );
|
|
|
|
if ( $this->filterLocal ) {
|
|
// Don't show local file usage
|
|
$where[] = 'gil_wiki != ' . $this->db->addQuotes( wfWikiId() );
|
|
}
|
|
|
|
// Set the continuation condition
|
|
$order = 'ASC';
|
|
if ( $this->offset ) {
|
|
$qTo = $this->db->addQuotes( $this->offset[0] );
|
|
$qWiki = $this->db->addQuotes( $this->offset[1] );
|
|
$qPage = intval( $this->offset[2] );
|
|
|
|
// Check which limit we got in order to determine which way to traverse rows
|
|
if ( $this->reversed ) {
|
|
// Reversed traversal; do not include offset row
|
|
$op1 = '<';
|
|
$op2 = '<';
|
|
$order = 'DESC';
|
|
} else {
|
|
// Normal traversal; include offset row
|
|
$op1 = '>';
|
|
$op2 = '>=';
|
|
$order = 'ASC';
|
|
}
|
|
|
|
$where[] = "(gil_to $op1 $qTo) OR " .
|
|
"(gil_to = $qTo AND gil_wiki $op1 $qWiki) OR " .
|
|
"(gil_to = $qTo AND gil_wiki = $qWiki AND gil_page $op2 $qPage)";
|
|
}
|
|
|
|
/* Perform select (Duh.) */
|
|
$res = $this->db->select( 'globalimagelinks',
|
|
array(
|
|
'gil_to',
|
|
'gil_wiki',
|
|
'gil_page',
|
|
'gil_page_namespace',
|
|
'gil_page_title'
|
|
),
|
|
$where,
|
|
__METHOD__,
|
|
array(
|
|
'ORDER BY' => "gil_to $order, gil_wiki $order, gil_page $order",
|
|
// Select an extra row to check whether we have more rows available
|
|
'LIMIT' => $this->limit + 1,
|
|
)
|
|
);
|
|
|
|
/* Process result */
|
|
// Always return the result in the same order; regardless whether reversed was specified
|
|
// reversed is really only used to determine from which direction the offset is
|
|
$rows = array();
|
|
foreach ( $res as $row ) {
|
|
$rows[] = $row;
|
|
}
|
|
if ( $this->reversed ) {
|
|
$rows = array_reverse( $rows );
|
|
}
|
|
|
|
// Build the result array
|
|
$count = 0;
|
|
$this->hasMore = false;
|
|
$this->result = array();
|
|
foreach ( $rows as $row ) {
|
|
$count++;
|
|
if ( $count > $this->limit ) {
|
|
// We've reached the extra row that indicates that there are more rows
|
|
$this->hasMore = true;
|
|
$this->lastRow = $row;
|
|
break;
|
|
}
|
|
|
|
if ( !isset( $this->result[$row->gil_to] ) ) {
|
|
$this->result[$row->gil_to] = array();
|
|
}
|
|
if ( !isset( $this->result[$row->gil_to][$row->gil_wiki] ) ) {
|
|
$this->result[$row->gil_to][$row->gil_wiki] = array();
|
|
}
|
|
|
|
$this->result[$row->gil_to][$row->gil_wiki][] = array(
|
|
'image' => $row->gil_to,
|
|
'id' => $row->gil_page,
|
|
'namespace' => $row->gil_page_namespace,
|
|
'title' => $row->gil_page_title,
|
|
'wiki' => $row->gil_wiki,
|
|
);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns the result set. The result is a 4 dimensional array
|
|
* (file, wiki, page), whose items are arrays with keys:
|
|
* - image or template: File name or template name
|
|
* - id: Page id
|
|
* - namespace: Page namespace text
|
|
* - title: Unprefixed page title
|
|
* - wiki: Wiki id
|
|
*
|
|
* @return array Result set
|
|
*/
|
|
public function getResult() {
|
|
return $this->result;
|
|
}
|
|
/**
|
|
* Returns a 3 dimensional array with the result of the first file. Useful
|
|
* if only one resource was queried.
|
|
*
|
|
* For further information see documentation of getResult()
|
|
*
|
|
* @return array Result set
|
|
*/
|
|
public function getSingleResult() {
|
|
if ( $this->result ) {
|
|
return current( $this->result );
|
|
} else {
|
|
return array();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Returns whether there are more results
|
|
*
|
|
* @return bool
|
|
*/
|
|
public function hasMore() {
|
|
return $this->hasMore;
|
|
}
|
|
|
|
/**
|
|
* Returns the result length
|
|
*
|
|
* @return int
|
|
*/
|
|
public function count() {
|
|
return count( $this->result );
|
|
}
|
|
}
|