RepoGroup.php 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258
  1. <?php
  2. /**
  3. * @defgroup FileRepo FileRepo
  4. *
  5. * @file
  6. * @ingroup FileRepo
  7. */
  8. /**
  9. * @ingroup FileRepo
  10. * Prioritized list of file repositories
  11. */
  12. class RepoGroup {
  13. var $localRepo, $foreignRepos, $reposInitialised = false;
  14. var $localInfo, $foreignInfo;
  15. protected static $instance;
  16. /**
  17. * Get a RepoGroup instance. At present only one instance of RepoGroup is
  18. * needed in a MediaWiki invocation, this may change in the future.
  19. */
  20. static function singleton() {
  21. if ( self::$instance ) {
  22. return self::$instance;
  23. }
  24. global $wgLocalFileRepo, $wgForeignFileRepos;
  25. self::$instance = new RepoGroup( $wgLocalFileRepo, $wgForeignFileRepos );
  26. return self::$instance;
  27. }
  28. /**
  29. * Destroy the singleton instance, so that a new one will be created next
  30. * time singleton() is called.
  31. */
  32. static function destroySingleton() {
  33. self::$instance = null;
  34. }
  35. /**
  36. * Set the singleton instance to a given object
  37. */
  38. static function setSingleton( $instance ) {
  39. self::$instance = $instance;
  40. }
  41. /**
  42. * Construct a group of file repositories.
  43. * @param array $data Array of repository info arrays.
  44. * Each info array is an associative array with the 'class' member
  45. * giving the class name. The entire array is passed to the repository
  46. * constructor as the first parameter.
  47. */
  48. function __construct( $localInfo, $foreignInfo ) {
  49. $this->localInfo = $localInfo;
  50. $this->foreignInfo = $foreignInfo;
  51. }
  52. /**
  53. * Search repositories for an image.
  54. * You can also use wfGetFile() to do this.
  55. * @param mixed $title Title object or string
  56. * @param mixed $time The 14-char timestamp the file should have
  57. * been uploaded, or false for the current version
  58. * @param mixed $flags FileRepo::FIND_ flags
  59. * @return File object or false if it is not found
  60. */
  61. function findFile( $title, $time = false, $flags = 0 ) {
  62. if ( !$this->reposInitialised ) {
  63. $this->initialiseRepos();
  64. }
  65. $image = $this->localRepo->findFile( $title, $time, $flags );
  66. if ( $image ) {
  67. return $image;
  68. }
  69. foreach ( $this->foreignRepos as $repo ) {
  70. $image = $repo->findFile( $title, $time, $flags );
  71. if ( $image ) {
  72. return $image;
  73. }
  74. }
  75. return false;
  76. }
  77. function findFiles( $titles ) {
  78. if ( !$this->reposInitialised ) {
  79. $this->initialiseRepos();
  80. }
  81. $titleObjs = array();
  82. foreach ( $titles as $title ) {
  83. if ( !( $title instanceof Title ) )
  84. $title = Title::makeTitleSafe( NS_FILE, $title );
  85. if ( $title )
  86. $titleObjs[$title->getDBkey()] = $title;
  87. }
  88. $images = $this->localRepo->findFiles( $titleObjs );
  89. foreach ( $this->foreignRepos as $repo ) {
  90. // Remove found files from $titleObjs
  91. foreach ( $images as $name => $image )
  92. if ( isset( $titleObjs[$name] ) )
  93. unset( $titleObjs[$name] );
  94. $images = array_merge( $images, $repo->findFiles( $titleObjs ) );
  95. }
  96. return $images;
  97. }
  98. /**
  99. * Interface for FileRepo::checkRedirect()
  100. */
  101. function checkRedirect( $title ) {
  102. if ( !$this->reposInitialised ) {
  103. $this->initialiseRepos();
  104. }
  105. $redir = $this->localRepo->checkRedirect( $title );
  106. if( $redir ) {
  107. return $redir;
  108. }
  109. foreach ( $this->foreignRepos as $repo ) {
  110. $redir = $repo->checkRedirect( $title );
  111. if ( $redir ) {
  112. return $redir;
  113. }
  114. }
  115. return false;
  116. }
  117. function findBySha1( $hash ) {
  118. if ( !$this->reposInitialised ) {
  119. $this->initialiseRepos();
  120. }
  121. $result = $this->localRepo->findBySha1( $hash );
  122. foreach ( $this->foreignRepos as $repo )
  123. $result = array_merge( $result, $repo->findBySha1( $hash ) );
  124. return $result;
  125. }
  126. /**
  127. * Get the repo instance with a given key.
  128. */
  129. function getRepo( $index ) {
  130. if ( !$this->reposInitialised ) {
  131. $this->initialiseRepos();
  132. }
  133. if ( $index === 'local' ) {
  134. return $this->localRepo;
  135. } elseif ( isset( $this->foreignRepos[$index] ) ) {
  136. return $this->foreignRepos[$index];
  137. } else {
  138. return false;
  139. }
  140. }
  141. /**
  142. * Get the repo instance by its name
  143. */
  144. function getRepoByName( $name ) {
  145. if ( !$this->reposInitialised ) {
  146. $this->initialiseRepos();
  147. }
  148. foreach ( $this->foreignRepos as $key => $repo ) {
  149. if ( $repo->name == $name)
  150. return $repo;
  151. }
  152. return false;
  153. }
  154. /**
  155. * Get the local repository, i.e. the one corresponding to the local image
  156. * table. Files are typically uploaded to the local repository.
  157. */
  158. function getLocalRepo() {
  159. return $this->getRepo( 'local' );
  160. }
  161. /**
  162. * Call a function for each foreign repo, with the repo object as the
  163. * first parameter.
  164. *
  165. * @param $callback callback The function to call
  166. * @param $params array Optional additional parameters to pass to the function
  167. */
  168. function forEachForeignRepo( $callback, $params = array() ) {
  169. foreach( $this->foreignRepos as $repo ) {
  170. $args = array_merge( array( $repo ), $params );
  171. if( call_user_func_array( $callback, $args ) ) {
  172. return true;
  173. }
  174. }
  175. return false;
  176. }
  177. /**
  178. * Does the installation have any foreign repos set up?
  179. * @return bool
  180. */
  181. function hasForeignRepos() {
  182. return (bool)$this->foreignRepos;
  183. }
  184. /**
  185. * Initialise the $repos array
  186. */
  187. function initialiseRepos() {
  188. if ( $this->reposInitialised ) {
  189. return;
  190. }
  191. $this->reposInitialised = true;
  192. $this->localRepo = $this->newRepo( $this->localInfo );
  193. $this->foreignRepos = array();
  194. foreach ( $this->foreignInfo as $key => $info ) {
  195. $this->foreignRepos[$key] = $this->newRepo( $info );
  196. }
  197. }
  198. /**
  199. * Create a repo class based on an info structure
  200. */
  201. protected function newRepo( $info ) {
  202. $class = $info['class'];
  203. return new $class( $info );
  204. }
  205. /**
  206. * Split a virtual URL into repo, zone and rel parts
  207. * @return an array containing repo, zone and rel
  208. */
  209. function splitVirtualUrl( $url ) {
  210. if ( substr( $url, 0, 9 ) != 'mwrepo://' ) {
  211. throw new MWException( __METHOD__.': unknown protoocl' );
  212. }
  213. $bits = explode( '/', substr( $url, 9 ), 3 );
  214. if ( count( $bits ) != 3 ) {
  215. throw new MWException( __METHOD__.": invalid mwrepo URL: $url" );
  216. }
  217. return $bits;
  218. }
  219. function getFileProps( $fileName ) {
  220. if ( FileRepo::isVirtualUrl( $fileName ) ) {
  221. list( $repoName, /* $zone */, /* $rel */ ) = $this->splitVirtualUrl( $fileName );
  222. if ( $repoName === '' ) {
  223. $repoName = 'local';
  224. }
  225. $repo = $this->getRepo( $repoName );
  226. return $repo->getFileProps( $fileName );
  227. } else {
  228. return File::getPropsFromPath( $fileName );
  229. }
  230. }
  231. }