MessageGroupCache.php

Go to the documentation of this file.
00001 <?php
00018 class MessageGroupCache {
00019     const NO_SOURCE = 1;
00020     const NO_CACHE = 2;
00021     const CHANGED = 3;
00022 
00026     protected $group;
00027 
00031     protected $cache;
00032 
00036     protected $code;
00037 
00043     public function __construct( $group, $code = 'en' ) {
00044         if ( is_object( $group ) ) {
00045             $this->group = $group;
00046         } else {
00047             $this->group = MessageGroups::getGroup( $group );
00048         }
00049         $this->code = $code;
00050     }
00051 
00056     public function exists() {
00057         return file_exists( $this->getCacheFileName() );
00058     }
00059 
00064     public function getKeys() {
00065         return unserialize( $this->open()->get( '#keys' ) );
00066     }
00067 
00072     public function getTimestamp() {
00073         return $this->open()->get( '#created' );
00074     }
00075 
00080     public function getUpdateTimestamp() {
00081         return $this->open()->get( '#updated' );
00082     }
00083 
00089     public function get( $key ) {
00090         return $this->open()->get( $key );
00091     }
00092 
00097     public function create( $created = false ) {
00098         $this->close(); // Close the reader instance just to be sure
00099 
00100         $messages = $this->group->load( $this->code );
00101         if ( !count( $messages ) && !( $this->group instanceof SingleFileBasedMessageGroup ) ) {
00102             if ( $this->exists() ) {
00103                 // Delete stale cache files
00104                 unlink( $this->getCacheFileName() );
00105             }
00106 
00107             return; // Don't create empty caches
00108         }
00109         $hash = md5( file_get_contents( $this->group->getSourceFilePath( $this->code ) ) );
00110 
00111         $cache = CdbWriter::open( $this->getCacheFileName() );
00112         $keys = array_keys( $messages );
00113         $cache->set( '#keys', serialize( $keys ) );
00114 
00115         foreach ( $messages as $key => $value ) {
00116             $cache->set( $key, $value );
00117         }
00118 
00119         $cache->set( '#created', $created ? $created : wfTimestamp() );
00120         $cache->set( '#updated', wfTimestamp() );
00121         $cache->set( '#filehash', $hash );
00122         $cache->set( '#msgcount', count( $messages ) );
00123         ksort( $messages );
00124         $cache->set( '#msghash', md5( serialize( $messages ) ) );
00125         $cache->set( '#version', '3' );
00126         $cache->close();
00127     }
00128 
00136     public function isValid( &$reason = 0 ) {
00137         $group = $this->group;
00138         $groupId = $group->getId();
00139 
00140         $filename = $group->getSourceFilePath( $this->code );
00141 
00142         if ( $group instanceof SingleFileBasedMessageGroup ) {
00143             $source = $group->getFFS()->read( $this->code ) !== false;
00144         } else {
00145             static $globCache = null;
00146             if ( !isset( $globCache[$groupId] ) ) {
00147                 $pattern = $group->getSourceFilePath( '*' );
00148                 $globCache[$groupId] = array_flip( glob( $pattern, GLOB_NOESCAPE ) );
00149                 // Definition file might not match the above pattern
00150                 $globCache[$groupId][$group->getSourceFilePath( 'en' )] = true;
00151             }
00152             $source = isset( $globCache[$groupId][$filename] );
00153         }
00154 
00155         $cache = $this->exists();
00156 
00157         // Timestamp and existence checks
00158         if ( !$cache && !$source ) {
00159             return true;
00160         } elseif ( !$cache && $source ) {
00161             $reason = self::NO_CACHE;
00162 
00163             return false;
00164         } elseif ( $cache && !$source ) {
00165             $reason = self::NO_SOURCE;
00166 
00167             return false;
00168         } elseif ( filemtime( $filename ) <= $this->get( '#updated' ) ) {
00169             return true;
00170         }
00171 
00172         // From now on cache and source file exists, but source file mtime is newer
00173         $created = $this->get( '#created' );
00174 
00175         // File hash check
00176         $newhash = md5( file_get_contents( $filename ) );
00177         if ( $this->get( '#filehash' ) === $newhash ) {
00178             // Update cache so that we don't need to compare hashes next time
00179             $this->create( $created );
00180 
00181             return true;
00182         }
00183 
00184         // Message count check
00185         $messages = $group->load( $this->code );
00186         // CDB converts numbers to strings
00187         $count = intval( $this->get( '#msgcount' ) );
00188         if ( $count !== count( $messages ) ) {
00189             // Number of messsages has changed
00190             $reason = self::CHANGED;
00191 
00192             return false;
00193         }
00194 
00195         // Content hash check
00196         ksort( $messages );
00197         if ( $this->get( '#msghash' ) === md5( serialize( $messages ) ) ) {
00198             // Update cache so that we don't need to do slow checks next time
00199             $this->create( $created );
00200 
00201             return true;
00202         }
00203 
00204         $reason = self::CHANGED;
00205 
00206         return false;
00207     }
00208 
00213     protected function open() {
00214         if ( $this->cache === null ) {
00215             $this->cache = CdbReader::open( $this->getCacheFileName() );
00216             if ( $this->cache->get( '#version' ) !== '3' ) {
00217                 $this->updateCacheFormat( $this->cache );
00218                 $this->close();
00219 
00220                 return $this->open();
00221             }
00222         }
00223 
00224         return $this->cache;
00225     }
00226 
00230     protected function close() {
00231         if ( $this->cache !== null ) {
00232             $this->cache->close();
00233             $this->cache = null;
00234         }
00235     }
00236 
00241     protected function getCacheFileName() {
00242         $cacheFileName = "translate_groupcache-{$this->group->getId()}-{$this->code}.cdb";
00243 
00244         return TranslateUtils::cacheFile( $cacheFileName );
00245     }
00246 
00251     protected function updateCacheFormat( $oldcache ) {
00252         // Read the data from the old format
00253         $conv = array(
00254             '#keys' => $oldcache->get( '<|keys#>' ),
00255             '#created' => $oldcache->get( '<|timestamp#>' ),
00256             '#updated' => wfTimestamp(),
00257             '#filehash' => $oldcache->get( '<|hash#>' ),
00258             '#version' => '3',
00259         );
00260         $conv['#msgcount'] = count( $conv['#keys'] );
00261 
00262         $messages = array();
00263         foreach ( unserialize( $conv['#keys'] ) as $key ) {
00264             $messages[$key] = $oldcache->get( $key );
00265         }
00266 
00267         ksort( $messages );
00268         $conv['#msghash'] = md5( serialize( $messages ) );
00269         $oldcache->close();
00270 
00271         // Store the data in new format
00272         $cache = CdbWriter::open( $this->getCacheFileName() );
00273         foreach ( $conv as $key => $value ) {
00274             $cache->set( $key, $value );
00275         }
00276         foreach ( $messages as $key => $value ) {
00277             $cache->set( $key, $value );
00278         }
00279         $cache->close();
00280     }
00281 }
Generated on Tue Oct 29 00:00:25 2013 for MediaWiki Translate Extension by  doxygen 1.6.3