Chủ đề nóng: Phương pháp kỷ luật tích cực - Cổ học tinh hoa - Những thói hư tật xấu của người Việt - Công lý: Việc đúng nên làm - Giáo án Điện tử - Sách giáo khoa - Học tiếng Anh - Bài giảng trực tuyến - Món ăn bài thuốc - Chăm sóc bà bầu - Môi trường - Tiết kiệm điện - Nhi khoa - Ung thư - Tác hại của thuốc lá - Các kỹ thuật dạy học tích cực
- Dạy học phát triển năng lực - Chương trình giáo dục phổ thông
Thành viên:Nguyenthephuc/Note: Kĩ thuật Job trong Mediawiki
Từ VLOS
CHÚ Ý: Từ mw 1.21, cách thức sử dụng lớp Job có thay đổi. Chi tiết xem: mw:Manual:Job_queue/For_developers
Mục lục
- 1 Kĩ thuật Job và ứng dụng
- 2 Cách viết phần mở rộng Job
-
3
Các
ví
dụ
- 3.1 includes\DoubleRedirectJob.php
- 3.2 includes\EmaillingJob.php
- 3.3 includes\EnotifNotifyJob.php
- 3.4 includes\HTMLCacheUpdate.php
- 3.5 includes\RefreshLinksJob.php
- 3.6 Tham khảo extensions\ReplaceText\ReplaceText.php
- 3.7 Tham khảo extensions\RenameUser\SpecialRenameuser.php
- 3.8 Tham khảo extensions\vlos\namhoc
Kĩ thuật Job và ứng dụng[sửa]
Kĩ thuật cho phép server xử lí các thao tác theo kiểu hàng đợi việc. Server sẽ thực thi các yêu cầu khi server không quá bận. Do vậy, kĩ thuật thường dùng để thực thi các công việc có tính hàng loạt.
Ứng dụng:
- sendemail
- delete pages (xóa tất cả các trang trong thể loại cần xóa)
- append content pages
- mutilupload
- Đăng kí nhận tin
- Gửi tin hàng loạt
Cách viết phần mở rộng Job[sửa]
Có thể chia làm 2 file: MyJob.php và MyExt.php
Nội dung file MyJob.php
class MyJob extends Job { function __construct( $title, $params, $id = 0 ) {//Job sẽ làm việc gì đó params với title parent::__construct( 'myJob', $title, $params, $id );//"myJob" tên Job đăng kí Hook } function run() { //do something return true;//trả về true nếu thành công, trả về false nếu thất bại } }
Nội dung file MyExt.php
$wgJobClasses['myJob'] = 'MyJob';//đăng ký một Job với tên là 'myJob' và class thực thi Job đó là 'MyJob' $wgAutoloadClasses['MyJob'] = $dir . 'MyJob.php';//nạp class //Triệu gọi //Tạo tham số đầu vào params $jobs = array(); foreach ( $res as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); if ( !$title ) { continue; } $jobs[] = new MyJob( $title, $params ); # Avoid excessive memory usage if ( count( $jobs ) > 10000 ) { Job::batchInsert( $jobs );//xếp Job vào hàng đợi $jobs = array(); } } Job::batchInsert( $jobs ); }
Các ví dụ[sửa]
includes\DoubleRedirectJob.php[sửa]
/** * Job to fix double redirects after moving a page * * @ingroup JobQueue */ class DoubleRedirectJob extends Job { var $reason, $redirTitle, $destTitleText; static $user; /** * Insert jobs into the job queue to fix redirects to the given title * @param $reason String: the reason for the fix, see message double-redirect-fixed-<reason> * @param $redirTitle Title: the title which has changed, redirects pointing to this title are fixed * @param $destTitle Not used */ public static function fixRedirects( $reason, $redirTitle, $destTitle = false ) { # Need to use the master to get the redirect table updated in the same transaction $dbw = wfGetDB( DB_MASTER ); $res = $dbw->select( array( 'redirect', 'page' ), array( 'page_namespace', 'page_title' ), array( 'page_id = rd_from', 'rd_namespace' => $redirTitle->getNamespace(), 'rd_title' => $redirTitle->getDBkey() ), __METHOD__ ); if ( !$res->numRows() ) { return; } $jobs = array(); foreach ( $res as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); if ( !$title ) { continue; } $jobs[] = new self( $title, array( 'reason' => $reason, 'redirTitle' => $redirTitle->getPrefixedDBkey() ) ); # Avoid excessive memory usage if ( count( $jobs ) > 10000 ) { Job::batchInsert( $jobs ); $jobs = array(); } } Job::batchInsert( $jobs ); } function __construct( $title, $params = false, $id = 0 ) { parent::__construct( 'fixDoubleRedirect', $title, $params, $id ); $this->reason = $params['reason']; $this->redirTitle = Title::newFromText( $params['redirTitle'] ); $this->destTitleText = !empty( $params['destTitle'] ) ? $params['destTitle'] : ''; } function run() { if ( !$this->redirTitle ) { $this->setLastError( 'Invalid title' ); return false; } $targetRev = Revision::newFromTitle( $this->title ); if ( !$targetRev ) { wfDebug( __METHOD__.": target redirect already deleted, ignoring\n" ); return true; } $text = $targetRev->getText(); $currentDest = Title::newFromRedirect( $text ); if ( !$currentDest || !$currentDest->equals( $this->redirTitle ) ) { wfDebug( __METHOD__.": Redirect has changed since the job was queued\n" ); return true; } # Check for a suppression tag (used e.g. in periodically archived discussions) $mw = MagicWord::get( 'staticredirect' ); if ( $mw->match( $text ) ) { wfDebug( __METHOD__.": skipping: suppressed with __STATICREDIRECT__\n" ); return true; } # Find the current final destination $newTitle = self::getFinalDestination( $this->redirTitle ); if ( !$newTitle ) { wfDebug( __METHOD__.": skipping: single redirect, circular redirect or invalid redirect destination\n" ); return true; } if ( $newTitle->equals( $this->redirTitle ) ) { # The redirect is already right, no need to change it # This can happen if the page was moved back (say after vandalism) wfDebug( __METHOD__.": skipping, already good\n" ); } # Preserve fragment (bug 14904) $newTitle = Title::makeTitle( $newTitle->getNamespace(), $newTitle->getDBkey(), $currentDest->getFragment() ); # Fix the text # Remember that redirect pages can have categories, templates, etc., # so the regex has to be fairly general $newText = preg_replace( '/ \[ \[ [^\]]* \] \] /x', '[[' . $newTitle->getFullText() . ']]', $text, 1 ); if ( $newText === $text ) { $this->setLastError( 'Text unchanged???' ); return false; } # Save it global $wgUser; $oldUser = $wgUser; $wgUser = $this->getUser(); $article = new Article( $this->title ); $reason = wfMsgForContent( 'double-redirect-fixed-' . $this->reason, $this->redirTitle->getPrefixedText(), $newTitle->getPrefixedText() ); $article->doEdit( $newText, $reason, EDIT_UPDATE | EDIT_SUPPRESS_RC ); $wgUser = $oldUser; return true; } /** * Get the final destination of a redirect * @return false if the specified title is not a redirect, or if it is a circular redirect */ public static function getFinalDestination( $title ) { $dbw = wfGetDB( DB_MASTER ); $seenTitles = array(); # Circular redirect check $dest = false; while ( true ) { $titleText = $title->getPrefixedDBkey(); if ( isset( $seenTitles[$titleText] ) ) { wfDebug( __METHOD__, "Circular redirect detected, aborting\n" ); return false; } $seenTitles[$titleText] = true; $row = $dbw->selectRow( array( 'redirect', 'page' ), array( 'rd_namespace', 'rd_title' ), array( 'rd_from=page_id', 'page_namespace' => $title->getNamespace(), 'page_title' => $title->getDBkey() ), __METHOD__ ); if ( !$row ) { # No redirect from here, chain terminates break; } else { $dest = $title = Title::makeTitle( $row->rd_namespace, $row->rd_title ); } } return $dest; } /** * Get a user object for doing edits, from a request-lifetime cache */ function getUser() { if ( !self::$user ) { self::$user = User::newFromName( wfMsgForContent( 'double-redirect-fixer' ), false ); if ( !self::$user->isLoggedIn() ) { self::$user->addToDatabase(); } } return self::$user; } }
includes\EmaillingJob.php[sửa]
/** * Old job used for sending single notification emails; * kept for backwards-compatibility * * @ingroup JobQueue */ class EmaillingJob extends Job { function __construct( $title, $params, $id = 0 ) { parent::__construct( 'sendMail', Title::newMainPage(), $params, $id ); } function run() { userMailer( $this->params['to'], $this->params['from'], $this->params['subj'], $this->params['body'], $this->params['replyto'] ); return true; } }
includes\EnotifNotifyJob.php[sửa]
/** * Job for email notification mails * * @ingroup JobQueue */ class EnotifNotifyJob extends Job { function __construct( $title, $params, $id = 0 ) { parent::__construct( 'enotifNotify', $title, $params, $id ); } function run() { $enotif = new EmailNotification(); // Get the user from ID (rename safe). Anons are 0, so defer to name. if( isset($this->params['editorID']) && $this->params['editorID'] ) { $editor = User::newFromId( $this->params['editorID'] ); // B/C, only the name might be given. } else { $editor = User::newFromName( $this->params['editor'], false ); } $enotif->actuallyNotifyOnPageChange( $editor, $this->title, $this->params['timestamp'], $this->params['summary'], $this->params['minorEdit'], $this->params['oldid'], $this->params['watchers'] ); return true; } }
includes\HTMLCacheUpdate.php[sửa]
/** * Class to invalidate the HTML cache of all the pages linking to a given title. * Small numbers of links will be done immediately, large numbers are pushed onto * the job queue. * * This class is designed to work efficiently with small numbers of links, and * to work reasonably well with up to ~10^5 links. Above ~10^6 links, the memory * and time requirements of loading all backlinked IDs in doUpdate() might become * prohibitive. The requirements measured at Wikimedia are approximately: * * memory: 48 bytes per row * time: 16us per row for the query plus processing * * The reason this query is done is to support partitioning of the job * by backlinked ID. The memory issue could be allieviated by doing this query in * batches, but of course LIMIT with an offset is inefficient on the DB side. * * The class is nevertheless a vast improvement on the previous method of using * Image::getLinksTo() and Title::touchArray(), which uses about 2KB of memory per * link. * * @ingroup Cache */ class HTMLCacheUpdate { public $mTitle, $mTable, $mPrefix, $mStart, $mEnd; public $mRowsPerJob, $mRowsPerQuery; function __construct( $titleTo, $table, $start = false, $end = false ) { global $wgUpdateRowsPerJob, $wgUpdateRowsPerQuery; $this->mTitle = $titleTo; $this->mTable = $table; $this->mStart = $start; $this->mEnd = $end; $this->mRowsPerJob = $wgUpdateRowsPerJob; $this->mRowsPerQuery = $wgUpdateRowsPerQuery; $this->mCache = $this->mTitle->getBacklinkCache(); } public function doUpdate() { if ( $this->mStart || $this->mEnd ) { $this->doPartialUpdate(); return; } # Get an estimate of the number of rows from the BacklinkCache $numRows = $this->mCache->getNumLinks( $this->mTable ); if ( $numRows > $this->mRowsPerJob * 2 ) { # Do fast cached partition $this->insertJobs(); } else { # Get the links from the DB $titleArray = $this->mCache->getLinks( $this->mTable ); # Check if the row count estimate was correct if ( $titleArray->count() > $this->mRowsPerJob * 2 ) { # Not correct, do accurate partition wfDebug( __METHOD__.": row count estimate was incorrect, repartitioning\n" ); $this->insertJobsFromTitles( $titleArray ); } else { $this->invalidateTitles( $titleArray ); } } wfRunHooks( 'HTMLCacheUpdate::doUpdate', array($this->mTitle) ); } /** * Update some of the backlinks, defined by a page ID range */ protected function doPartialUpdate() { $titleArray = $this->mCache->getLinks( $this->mTable, $this->mStart, $this->mEnd ); if ( $titleArray->count() <= $this->mRowsPerJob * 2 ) { # This partition is small enough, do the update $this->invalidateTitles( $titleArray ); } else { # Partitioning was excessively inaccurate. Divide the job further. # This can occur when a large number of links are added in a short # period of time, say by updating a heavily-used template. $this->insertJobsFromTitles( $titleArray ); } } /** * Partition the current range given by $this->mStart and $this->mEnd, * using a pre-calculated title array which gives the links in that range. * Queue the resulting jobs. */ protected function insertJobsFromTitles( $titleArray ) { # We make subpartitions in the sense that the start of the first job # will be the start of the parent partition, and the end of the last # job will be the end of the parent partition. $jobs = array(); $start = $this->mStart; # start of the current job $numTitles = 0; foreach ( $titleArray as $title ) { $id = $title->getArticleID(); # $numTitles is now the number of titles in the current job not # including the current ID if ( $numTitles >= $this->mRowsPerJob ) { # Add a job up to but not including the current ID $params = array( 'table' => $this->mTable, 'start' => $start, 'end' => $id - 1 ); $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); $start = $id; $numTitles = 0; } $numTitles++; } # Last job $params = array( 'table' => $this->mTable, 'start' => $start, 'end' => $this->mEnd ); $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); wfDebug( __METHOD__.": repartitioning into " . count( $jobs ) . " jobs\n" ); if ( count( $jobs ) < 2 ) { # I don't think this is possible at present, but handling this case # makes the code a bit more robust against future code updates and # avoids a potential infinite loop of repartitioning wfDebug( __METHOD__.": repartitioning failed!\n" ); $this->invalidateTitles( $titleArray ); return; } Job::batchInsert( $jobs ); } protected function insertJobs() { $batches = $this->mCache->partition( $this->mTable, $this->mRowsPerJob ); if ( !$batches ) { return; } $jobs = array(); foreach ( $batches as $batch ) { $params = array( 'table' => $this->mTable, 'start' => $batch[0], 'end' => $batch[1], ); $jobs[] = new HTMLCacheUpdateJob( $this->mTitle, $params ); } Job::batchInsert( $jobs ); } /** * Invalidate a range of pages, right now * @deprecated */ public function invalidate( $startId = false, $endId = false ) { $titleArray = $this->mCache->getLinks( $this->mTable, $startId, $endId ); $this->invalidateTitles( $titleArray ); } /** * Invalidate an array (or iterator) of Title objects, right now */ protected function invalidateTitles( $titleArray ) { global $wgUseFileCache, $wgUseSquid; $dbw = wfGetDB( DB_MASTER ); $timestamp = $dbw->timestamp(); # Get all IDs in this query into an array $ids = array(); foreach ( $titleArray as $title ) { $ids[] = $title->getArticleID(); } if ( !$ids ) { return; } # Update page_touched $batches = array_chunk( $ids, $this->mRowsPerQuery ); foreach ( $batches as $batch ) { $dbw->update( 'page', array( 'page_touched' => $timestamp ), array( 'page_id IN (' . $dbw->makeList( $batch ) . ')' ), __METHOD__ ); } # Update squid if ( $wgUseSquid ) { $u = SquidUpdate::newFromTitles( $titleArray ); $u->doUpdate(); } # Update file cache if ( $wgUseFileCache ) { foreach ( $titleArray as $title ) { HTMLFileCache::clearFileCache( $title ); } } } } /** * Job wrapper for HTMLCacheUpdate. Gets run whenever a related * job gets called from the queue. * * @ingroup JobQueue */ class HTMLCacheUpdateJob extends Job { var $table, $start, $end; /** * Construct a job * @param $title Title: the title linked to * @param $params Array: job parameters (table, start and end page_ids) * @param $id Integer: job id */ function __construct( $title, $params, $id = 0 ) { parent::__construct( 'htmlCacheUpdate', $title, $params, $id ); $this->table = $params['table']; $this->start = $params['start']; $this->end = $params['end']; } public function run() { $update = new HTMLCacheUpdate( $this->title, $this->table, $this->start, $this->end ); $update->doUpdate(); return true; } }
includes\RefreshLinksJob.php[sửa]
/** * Background job to update links for a given title. * * @ingroup JobQueue */ class RefreshLinksJob extends Job { function __construct( $title, $params = '', $id = 0 ) { parent::__construct( 'refreshLinks', $title, $params, $id ); } /** * Run a refreshLinks job * @return boolean success */ function run() { global $wgParser; wfProfileIn( __METHOD__ ); $linkCache = LinkCache::singleton(); $linkCache->clear(); if ( is_null( $this->title ) ) { $this->error = "refreshLinks: Invalid title"; wfProfileOut( __METHOD__ ); return false; } $revision = Revision::newFromTitle( $this->title ); if ( !$revision ) { $this->error = 'refreshLinks: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut( __METHOD__ ); return false; } wfProfileIn( __METHOD__.'-parse' ); $options = new ParserOptions; $parserOutput = $wgParser->parse( $revision->getText(), $this->title, $options, true, true, $revision->getId() ); wfProfileOut( __METHOD__.'-parse' ); wfProfileIn( __METHOD__.'-update' ); $update = new LinksUpdate( $this->title, $parserOutput, false ); $update->doUpdate(); wfProfileOut( __METHOD__.'-update' ); wfProfileOut( __METHOD__ ); return true; } } /** * Background job to update links for a given title. * Newer version for high use templates. * * @ingroup JobQueue */ class RefreshLinksJob2 extends Job { function __construct( $title, $params, $id = 0 ) { parent::__construct( 'refreshLinks2', $title, $params, $id ); } /** * Run a refreshLinks2 job * @return boolean success */ function run() { global $wgParser; wfProfileIn( __METHOD__ ); $linkCache = LinkCache::singleton(); $linkCache->clear(); if( is_null( $this->title ) ) { $this->error = "refreshLinks2: Invalid title"; wfProfileOut( __METHOD__ ); return false; } if( !isset($this->params['start']) || !isset($this->params['end']) ) { $this->error = "refreshLinks2: Invalid params"; wfProfileOut( __METHOD__ ); return false; } $titles = $this->title->getBacklinkCache()->getLinks( 'templatelinks', $this->params['start'], $this->params['end']); # Not suitable for page load triggered job running! # Gracefully switch to refreshLinks jobs if this happens. if( php_sapi_name() != 'cli' ) { $jobs = array(); foreach ( $titles as $title ) { $jobs[] = new RefreshLinksJob( $title, '' ); } Job::batchInsert( $jobs ); return true; } # Re-parse each page that transcludes this page and update their tracking links... foreach ( $titles as $title ) { $revision = Revision::newFromTitle( $title ); if ( !$revision ) { $this->error = 'refreshLinks: Article not found "' . $title->getPrefixedDBkey() . '"'; wfProfileOut( __METHOD__ ); return false; } wfProfileIn( __METHOD__.'-parse' ); $options = new ParserOptions; $parserOutput = $wgParser->parse( $revision->getText(), $title, $options, true, true, $revision->getId() ); wfProfileOut( __METHOD__.'-parse' ); wfProfileIn( __METHOD__.'-update' ); $update = new LinksUpdate( $title, $parserOutput, false ); $update->doUpdate(); wfProfileOut( __METHOD__.'-update' ); wfWaitForSlaves( 5 ); } wfProfileOut( __METHOD__ ); return true; } }
Tham khảo extensions\ReplaceText\ReplaceText.php[sửa]
# File: ReplaceText.php $wgAutoloadClasses['ReplaceTextJob'] = $rtgIP . 'ReplaceTextJob.php'; $wgJobClasses['replaceText'] = 'ReplaceTextJob'; # File: ReplaceTextJob.php /** * Background job to replace text in a given page * - based on /includes/RefreshLinksJob.php * * @author Yaron Koren * @author Ankit Garg */ class ReplaceTextJob extends Job { function __construct( $title, $params = '', $id = 0 ) { parent::__construct( 'replaceText', $title, $params, $id ); } /** * Run a replaceText job * @return boolean success */ function run() { wfProfileIn( __METHOD__ ); if ( is_null( $this->title ) ) { $this->error = "replaceText: Invalid title"; wfProfileOut( __METHOD__ ); return false; } if ( array_key_exists( 'move_page', $this->params ) ) { global $wgUser; $actual_user = $wgUser; $wgUser = User::newFromId( $this->params['user_id'] ); $cur_page_name = $this->title->getText(); if ( $this->params['use_regex'] ) { $new_page_name = preg_replace( "/".$this->params['target_str']."/U", $this->params['replacement_str'], $cur_page_name ); } else { $new_page_name = str_replace( $this->params['target_str'], $this->params['replacement_str'], $cur_page_name ); } $new_title = Title::newFromText( $new_page_name, $this->title->getNamespace() ); $reason = $this->params['edit_summary']; $create_redirect = $this->params['create_redirect']; $this->title->moveTo( $new_title, true, $reason, $create_redirect ); if ( $this->params['watch_page'] ) { $article = new Article( $new_title ); $article->doWatch(); } $wgUser = $actual_user; } else { $article = new Article( $this->title ); if ( !$article ) { $this->error = 'replaceText: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut( __METHOD__ ); return false; } wfProfileIn( __METHOD__ . '-replace' ); $article_text = $article->fetchContent(); $target_str = $this->params['target_str']; $replacement_str = $this->params['replacement_str']; $num_matches; if ( $this->params['use_regex'] ) { $new_text = preg_replace( '/'.$target_str.'/U', $replacement_str, $article_text, -1, $num_matches ); } else { $new_text = str_replace( $target_str, $replacement_str, $article_text, $num_matches ); } // if there's at least one replacement, modify the page, // using the passed-in edit summary if ( $num_matches > 0 ) { // change global $wgUser variable to the one // specified by the job only for the extent of // this replacement global $wgUser; $actual_user = $wgUser; $wgUser = User::newFromId( $this->params['user_id'] ); $edit_summary = $this->params['edit_summary']; $flags = EDIT_MINOR; //if ( $wgUser->isAllowed( 'bot' ) ) $flags |= EDIT_FORCE_BOT; $article->doEdit( $new_text, $edit_summary, $flags ); $wgUser = $actual_user; } wfProfileOut( __METHOD__ . '-replace' ); } wfProfileOut( __METHOD__ ); return true; } } //Cách gọi Job $jobs = array(); foreach ( $wgRequest->getValues() as $key => $value ) { if ( $value == '1' && $key !== 'replace' ) { if ( strpos( $key, 'move-' ) !== false ) { $title = Title::newFromID( substr( $key, 5 ) ); $replacement_params['move_page'] = true; } else { $title = Title::newFromID( $key ); } if ( $title !== null ) $jobs[] = new ReplaceTextJob( $title, $replacement_params ); } } Job::batchInsert( $jobs ); $count = $wgLang->formatNum( count( $jobs ) ); $wgOut->addWikiMsg( 'replacetext_success', "<tt><nowiki>{$this->target}</nowiki></tt>", "<tt><nowiki>{$this->replacement}</nowiki></tt>", $count );
Tham khảo extensions\RenameUser\SpecialRenameuser.php[sửa]
# File: SpecialRenameuser.php $wgAutoloadClasses['RenameUserJob'] = dirname(__FILE__) . '/RenameUserJob.php'; $wgJobClasses['renameUser'] = 'RenameUserJob'; # File: RenameUserJob.php /** * Custom job to perform updates on tables in busier environments */ class RenameUserJob extends Job { /** * Constructor * * @param Title $title Associated title * @param array $params Job parameters */ public function __construct( $title, $params ) { parent::__construct( 'renameUser', $title, $params ); } /** * Execute the job * * @return bool */ public function run() { $dbw = wfGetDB( DB_MASTER ); extract( $this->params ); # Conditions like "*_user_text = 'x' $conds = array( $column => $oldname ); # If user ID given, add that to condition to avoid rename collisions. if( isset($userID) ) { $conds[$uidColumn] = $userID; } # Bound by timestamp if given if( isset($timestampColumn) ) { $conds[] = "$timestampColumn >= '$minTimestamp'"; $conds[] = "$timestampColumn <= '$maxTimestamp'"; # Otherwise, bound by key (B/C) } else if( isset($uniqueKey) ) { $conds[$uniqueKey] = $keyId; } else { wfDebug( 'RenameUserJob::run - invalid job row given' ); // this shouldn't happen return false; } # Update a chuck of rows! $dbw->update( $table, array( $column => $newname ), $conds, __METHOD__ ); # Special case: revisions may be deleted while renaming... if( $table == 'revision' && isset($timestampColumn) ) { $actual = $dbw->affectedRows(); # If some revisions were not renamed, they may have been deleted. # Do a pass on the archive table to get these straglers... if( $actual < $count ) { $dbw->update( 'archive', array( 'ar_user_text' => $newname ), array( 'ar_user_text' => $oldname, 'ar_user' => $userID, // No user,rev_id index, so use timestamp to bound // the rows. This can use the user,timestamp index. "ar_timestamp >= '$minTimestamp'", "ar_timestamp <= '$maxTimestamp'"), __METHOD__ ); } } # Special case: revisions may be restored while renaming... if( $table == 'archive' && isset($timestampColumn) ) { $actual = $dbw->affectedRows(); # If some revisions were not renamed, they may have been restored. # Do a pass on the revision table to get these straglers... if( $actual < $count ) { $dbw->update( 'revision', array( 'rev_user_text' => $newname ), array( 'rev_user_text' => $oldname, 'rev_user' => $userID, // No user,rev_id index, so use timestamp to bound // the rows. This can use the user,timestamp index. "rev_timestamp >= '$minTimestamp'", "rev_timestamp <= '$maxTimestamp'"), __METHOD__ ); } } return true; } }
Tham khảo extensions\vlos\namhoc[sửa]
file Namhoc.php
<?php # Alert the user that this is not a valid entry point to MediaWiki if they try to access the special pages file directly. if (!defined('MEDIAWIKI')) { echo <<<EOT To install my extension, put the following line in LocalSettings.php: require_once( "\$IP/extensions/vlos/namhoc/Namhoc.php" ); EOT; exit( 1 ); } $wgExtensionCredits['specialpage'][] = array( 'name' => 'Namhoc', 'author' => 'Nguyen The Phuc', 'url' => 'http://www.thuvienkhoahoc.com', 'description' => 'Default description message', 'descriptionmsg' => 'namhoc-desc', 'version' => '0.0.0', ); $dir = dirname(__FILE__) . '/'; $wgExtensionMessagesFiles['Namhoc'] = $dir . 'Namhoc.i18n.php'; # Location of a messages file (Tell MediaWiki to load this file) $wgExtensionAliasesFiles['Namhoc'] = $dir . 'Namhoc.alias.php'; //Job $wgJobClasses['insertNamhoc'] = 'NamhocJob'; $wgAutoloadClasses['SpecialNamhoc'] = $dir . 'SpecialNamhoc.php'; # Location of the SpecialNamhoc class (Tell MediaWiki to load this file) $wgAutoloadClasses['NamhocJob'] = $dir . 'NamhocJob.php'; // This extension uses its own permission type, 'namhoc' $wgAvailableRights[] = 'namhoc'; $wgGroupPermissions['sysop']['namhoc'] = true; // maintenance, login, changes, media, users, highuse, pages, redirects, pagetools, wiki, other // (chi tiet xem file DefaultSettings.php) $wgSpecialPages['Namhoc'] = 'SpecialNamhoc'; # Tell MediaWiki about the new special page and its class name $wgSpecialPageGroups['Namhoc'] = 'wiki'; $wgHooks['AdminLinks'][] = 'nhAddToAdminLinks'; // This function should really go into a "ReplaceText_body.php" file. function nhAddToAdminLinks( &$admin_links_tree ) { $general_section = $admin_links_tree->getSection( wfMsg( 'adminlinks_general' ) ); $extensions_row = $general_section->getRow( 'extensions' ); if ( is_null( $extensions_row ) ) { $extensions_row = new ALRow( 'extensions' ); $general_section->addRow( $extensions_row ); } $extensions_row->addItem( ALItem::newFromSpecialPage( 'Namhoc' ) ); return true; }
file NamhocJob.php
<?php class NamhocJob extends Job { function __construct( $title, $params = '', $id = 0 ) { parent::__construct( 'insertNamhoc', $title, $params, $id ); } /** * Run a insertNamhoc job * @return boolean success */ function run() { wfProfileIn( __METHOD__ ); if ( is_null( $this->title ) ) { $this->error = "insertNamhoc: Invalid title"; wfProfileOut( __METHOD__ ); return false; } $article = new Article( $this->title ); if ( !$article ) { $this->error = 'insertNamhoc: Article not found "' . $this->title->getPrefixedDBkey() . '"'; wfProfileOut( __METHOD__ ); return false; } wfProfileIn( __METHOD__ . '-namhoc' ); $article_text = $article->fetchContent(); $more_str = $this->params['more_str']; $new_text = $article_text."\n$more_str"; global $wgUser; $actual_user = $wgUser; $wgUser = User::newFromId( $this->params['user_id'] ); $edit_summary = $this->params['edit_summary']; $flags = EDIT_MINOR; $flags |= EDIT_FORCE_BOT; $article->doEdit( $new_text, $edit_summary, $flags ); $wgUser = $actual_user; wfProfileOut( __METHOD__ . '-namhoc' ); wfProfileOut( __METHOD__ ); return true; } }
file SpecialNamhoc.php
function fixNamhoc(){ global $wgUser, $wgOut, $wgRequest, $wgLang; $this->cats = $wgRequest->getText( 'cats' ); $this->more_str = $wgRequest->getText( 'more_str' ); if ( $wgRequest->getCheck( 'continue' ) ) { if ( $this->more_str === '' ) { $this->showForm( 'namhoc_givetarget' ); return; }elseif ($this->cats === ''){ $this->showForm( 'namhoc_givesource' ); return; }else{ $res = $this->getPages(); $jobs = array(); $params = array(); $params['user_id'] = $wgUser->getId(); $params['more_str'] = $this->more_str; $params['edit_summary'] = wfMsgForContent( 'namhoc-editsummary', $this->more_str ); $count=0; foreach ( $res as $row ) { $title = Title::makeTitle( $row->page_namespace, $row->page_title ); if ( !$title ) { continue; } $jobs[] = new NamhocJob( $title, $params ); # Avoid excessive memory usage if ( count( $jobs ) > 10000 ) { Job::batchInsert( $jobs ); $jobs = array(); $count = 0; } } Job::batchInsert( $jobs ); $count += count( $jobs ); $total = $wgLang->formatNum( $count ); $wgOut->addWikiMsg( 'namhoc_success', "<tt><nowiki>{$this->more_str}</nowiki></tt>", $total ); return; } } // if we're still here, show the starting form $this->showForm(); }
Các ghi chú của cùng tác giả
- So sánh điểm kì thi tốt nghiệp trung học của Hà Giang và cả nước
- Học làm cha, làm mẹ
- Đọc sách 2 giờ mỗi ngày (Từ 4-6h sáng)
- Rễ, thân cành, và lá
- Sự trở lại của các thành bang
- Việt Nam học được gì từ bài học Phần Lan trong đổi mới giáo dục
- Đằng sau sự thành công của giáo dục Phần Lan là gì?
- Bí mật trong tuyển chọn và đào tạo giáo viên Phần Lan
- Chiến tranh và khó khăn - lý do khiến giáo dục Việt Nam khó phát triển
- Năng lực và các khái niệm liên quan