MediaWiki  REL1_31
CategoryFinder.php
Go to the documentation of this file.
1 <?php
24 
50  protected $articles = [];
51 
53  protected $deadend = [];
54 
56  protected $parents = [];
57 
59  protected $next = [];
60 
62  protected $maxdepth = -1;
63 
65  protected $targets = [];
66 
68  protected $name2id = [];
69 
71  protected $mode;
72 
74  protected $dbr;
75 
87  public function seed( $articleIds, $categories, $mode = 'AND', $maxdepth = -1 ) {
88  $this->articles = $articleIds;
89  $this->next = $articleIds;
90  $this->mode = $mode;
91  $this->maxdepth = $maxdepth;
92 
93  # Set the list of target categories; convert them to DBKEY form first
94  $this->targets = [];
95  foreach ( $categories as $c ) {
96  $ct = Title::makeTitleSafe( NS_CATEGORY, $c );
97  if ( $ct ) {
98  $c = $ct->getDBkey();
99  $this->targets[$c] = $c;
100  }
101  }
102  }
103 
109  public function run() {
110  $this->dbr = wfGetDB( DB_REPLICA );
111 
112  $i = 0;
113  $dig = true;
114  while ( count( $this->next ) && $dig ) {
115  $this->scanNextLayer();
116 
117  // Is there any depth limit?
118  if ( $this->maxdepth !== -1 ) {
119  $dig = $i < $this->maxdepth;
120  $i++;
121  }
122  }
123 
124  # Now check if this applies to the individual articles
125  $ret = [];
126 
127  foreach ( $this->articles as $article ) {
128  $conds = $this->targets;
129  if ( $this->check( $article, $conds ) ) {
130  # Matches the conditions
131  $ret[] = $article;
132  }
133  }
134  return $ret;
135  }
136 
141  public function getParents() {
142  return $this->parents;
143  }
144 
152  private function check( $id, &$conds, $path = [] ) {
153  // Check for loops and stop!
154  if ( in_array( $id, $path ) ) {
155  return false;
156  }
157 
158  $path[] = $id;
159 
160  # Shortcut (runtime paranoia): No conditions=all matched
161  if ( count( $conds ) == 0 ) {
162  return true;
163  }
164 
165  if ( !isset( $this->parents[$id] ) ) {
166  return false;
167  }
168 
169  # iterate through the parents
170  foreach ( $this->parents[$id] as $p ) {
171  $pname = $p->cl_to;
172 
173  # Is this a condition?
174  if ( isset( $conds[$pname] ) ) {
175  # This key is in the category list!
176  if ( $this->mode == 'OR' ) {
177  # One found, that's enough!
178  $conds = [];
179  return true;
180  } else {
181  # Assuming "AND" as default
182  unset( $conds[$pname] );
183  if ( count( $conds ) == 0 ) {
184  # All conditions met, done
185  return true;
186  }
187  }
188  }
189 
190  # Not done yet, try sub-parents
191  if ( !isset( $this->name2id[$pname] ) ) {
192  # No sub-parent
193  continue;
194  }
195  $done = $this->check( $this->name2id[$pname], $conds, $path );
196  if ( $done || count( $conds ) == 0 ) {
197  # Subparents have done it!
198  return true;
199  }
200  }
201  return false;
202  }
203 
207  private function scanNextLayer() {
208  # Find all parents of the article currently in $this->next
209  $layer = [];
210  $res = $this->dbr->select(
211  /* FROM */ 'categorylinks',
212  /* SELECT */ [ 'cl_to', 'cl_from' ],
213  /* WHERE */ [ 'cl_from' => $this->next ],
214  __METHOD__ . '-1'
215  );
216  foreach ( $res as $o ) {
217  $k = $o->cl_to;
218 
219  # Update parent tree
220  if ( !isset( $this->parents[$o->cl_from] ) ) {
221  $this->parents[$o->cl_from] = [];
222  }
223  $this->parents[$o->cl_from][$k] = $o;
224 
225  # Ignore those we already have
226  if ( in_array( $k, $this->deadend ) ) {
227  continue;
228  }
229 
230  if ( isset( $this->name2id[$k] ) ) {
231  continue;
232  }
233 
234  # Hey, new category!
235  $layer[$k] = $k;
236  }
237 
238  $this->next = [];
239 
240  # Find the IDs of all category pages in $layer, if they exist
241  if ( count( $layer ) > 0 ) {
242  $res = $this->dbr->select(
243  /* FROM */ 'page',
244  /* SELECT */ [ 'page_id', 'page_title' ],
245  /* WHERE */ [ 'page_namespace' => NS_CATEGORY, 'page_title' => $layer ],
246  __METHOD__ . '-2'
247  );
248  foreach ( $res as $o ) {
249  $id = $o->page_id;
250  $name = $o->page_title;
251  $this->name2id[$name] = $id;
252  $this->next[] = $id;
253  unset( $layer[$name] );
254  }
255  }
256 
257  # Mark dead ends
258  foreach ( $layer as $v ) {
259  $this->deadend[$v] = $v;
260  }
261  }
262 }
CategoryFinder\$parents
array $parents
Array of [ ID => [] ].
Definition: CategoryFinder.php:56
CategoryFinder\$articles
int[] $articles
The original article IDs passed to the seed function.
Definition: CategoryFinder.php:50
CategoryFinder\$maxdepth
int $maxdepth
Max layer depth.
Definition: CategoryFinder.php:62
CategoryFinder\$mode
string $mode
"AND" or "OR"
Definition: CategoryFinder.php:71
use
Apache License January AND DISTRIBUTION Definitions License shall mean the terms and conditions for use
Definition: APACHE-LICENSE-2.0.txt:10
array
the array() calling protocol came about after MediaWiki 1.4rc1.
$ret
null means default in associative array with keys and values unescaped Should be merged with default with a value of false meaning to suppress the attribute in associative array with keys and values unescaped noclasses & $ret
Definition: hooks.txt:2005
CategoryFinder\$targets
array $targets
Array of DBKEY category names.
Definition: CategoryFinder.php:65
$res
$res
Definition: database.txt:21
CategoryFinder\scanNextLayer
scanNextLayer()
Scans a "parent layer" of the articles/categories in $this->next.
Definition: CategoryFinder.php:207
php
injection txt This is an overview of how MediaWiki makes use of dependency injection The design described here grew from the discussion of RFC T384 The term dependency this means that anything an object needs to operate should be injected from the the object itself should only know narrow no concrete implementation of the logic it relies on The requirement to inject everything typically results in an architecture that based on two main types of and essentially stateless service objects that use other service objects to operate on the value objects As of the beginning MediaWiki is only starting to use the DI approach Much of the code still relies on global state or direct resulting in a highly cyclical dependency which acts as the top level factory for services in MediaWiki which can be used to gain access to default instances of various services MediaWikiServices however also allows new services to be defined and default services to be redefined Services are defined or redefined by providing a callback the instantiator that will return a new instance of the service When it will create an instance of MediaWikiServices and populate it with the services defined in the files listed by thereby bootstrapping the DI framework Per $wgServiceWiringFiles lists includes ServiceWiring php
Definition: injection.txt:37
Wikimedia\Rdbms\IDatabase
Basic database interface for live and lazy-loaded relation database handles.
Definition: IDatabase.php:38
CategoryFinder\check
check( $id, &$conds, $path=[])
This functions recurses through the parent representation, trying to match the conditions.
Definition: CategoryFinder.php:152
CategoryFinder\run
run()
Iterates through the parent tree starting with the seed values, then checks the articles if they matc...
Definition: CategoryFinder.php:109
wfGetDB
wfGetDB( $db, $groups=[], $wiki=false)
Get a Database object.
Definition: GlobalFunctions.php:2812
DB_REPLICA
const DB_REPLICA
Definition: defines.php:25
NS_CATEGORY
const NS_CATEGORY
Definition: Defines.php:88
CategoryFinder\$next
array $next
Array of article/category IDs.
Definition: CategoryFinder.php:59
CategoryFinder\seed
seed( $articleIds, $categories, $mode='AND', $maxdepth=-1)
Initializes the instance.
Definition: CategoryFinder.php:87
Title\makeTitleSafe
static makeTitleSafe( $ns, $title, $fragment='', $interwiki='')
Create a new Title from a namespace index and a DB key.
Definition: Title.php:562
CategoryFinder
The "CategoryFinder" class takes a list of articles, creates an internal representation of all their ...
Definition: CategoryFinder.php:48
$name
Allows to change the fields on the form that will be generated $name
Definition: hooks.txt:302
CategoryFinder\$name2id
array $name2id
Definition: CategoryFinder.php:68
$path
$path
Definition: NoLocalSettings.php:25
as
This document is intended to provide useful advice for parties seeking to redistribute MediaWiki to end users It s targeted particularly at maintainers for Linux since it s been observed that distribution packages of MediaWiki often break We ve consistently had to recommend that users seeking support use official tarballs instead of their distribution s and this often solves whatever problem the user is having It would be nice if this could such as
Definition: distributors.txt:22
CategoryFinder\getParents
getParents()
Get the parents.
Definition: CategoryFinder.php:141
$article
Using a hook running we can avoid having all this option specific stuff in our mainline code Using the function array $article
Definition: hooks.txt:77
CategoryFinder\$dbr
IDatabase $dbr
Read-DB replica DB.
Definition: CategoryFinder.php:74
CategoryFinder\$deadend
array $deadend
Array of DBKEY category names for categories that don't have a page.
Definition: CategoryFinder.php:53