1<?php
2/**
3 * Lock manager registration handling.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup LockManager
22 */
23use MediaWiki\Logger\LoggerFactory;
24use MediaWiki\MediaWikiServices;
25use Wikimedia\Rdbms\LBFactory;
26
27/**
28 * Class to handle file lock manager registration
29 *
30 * @ingroup LockManager
31 * @since 1.19
32 */
33class LockManagerGroup {
34	/** @var string domain (usually wiki ID) */
35	protected $domain;
36
37	/** @var LBFactory */
38	protected $lbFactory;
39
40	/** @var array Array of (name => ('class' => ..., 'config' => ..., 'instance' => ...)) */
41	protected $managers = [];
42
43	/**
44	 * Do not call this directly. Use LockManagerGroupFactory.
45	 *
46	 * @param string $domain Domain (usually wiki ID)
47	 * @param array[] $lockManagerConfigs In format of $wgLockManagers
48	 * @param LBFactory $lbFactory
49	 */
50	public function __construct( $domain, array $lockManagerConfigs, LBFactory $lbFactory ) {
51		$this->domain = $domain;
52		$this->lbFactory = $lbFactory;
53
54		foreach ( $lockManagerConfigs as $config ) {
55			$config['domain'] = $this->domain;
56			if ( !isset( $config['name'] ) ) {
57				throw new Exception( "Cannot register a lock manager with no name." );
58			}
59			$name = $config['name'];
60			if ( !isset( $config['class'] ) ) {
61				throw new Exception( "Cannot register lock manager `{$name}` with no class." );
62			}
63			$class = $config['class'];
64			unset( $config['class'] ); // lock manager won't need this
65			$this->managers[$name] = [
66				'class' => $class,
67				'config' => $config,
68				'instance' => null
69			];
70		}
71	}
72
73	/**
74	 * @deprecated since 1.34, use LockManagerGroupFactory
75	 *
76	 * @param bool|string $domain Domain (usually wiki ID). Default: false.
77	 * @return LockManagerGroup
78	 */
79	public static function singleton( $domain = false ) {
80		return MediaWikiServices::getInstance()->getLockManagerGroupFactory()
81			->getLockManagerGroup( $domain );
82	}
83
84	/**
85	 * Destroy the singleton instances
86	 *
87	 * @deprecated since 1.34, use resetServiceForTesting() on LockManagerGroupFactory
88	 */
89	public static function destroySingletons() {
90		MediaWikiServices::getInstance()->resetServiceForTesting( 'LockManagerGroupFactory' );
91	}
92
93	/**
94	 * Get the lock manager object with a given name
95	 *
96	 * @param string $name
97	 * @return LockManager
98	 * @throws Exception
99	 */
100	public function get( $name ) {
101		if ( !isset( $this->managers[$name] ) ) {
102			throw new Exception( "No lock manager defined with the name `$name`." );
103		}
104		// Lazy-load the actual lock manager instance
105		if ( !isset( $this->managers[$name]['instance'] ) ) {
106			$class = $this->managers[$name]['class'];
107			'@phan-var string $class';
108			$config = $this->managers[$name]['config'];
109			$config['logger'] = LoggerFactory::getInstance( 'LockManager' );
110
111			$this->managers[$name]['instance'] = new $class( $config );
112		}
113
114		return $this->managers[$name]['instance'];
115	}
116
117	/**
118	 * Get the config array for a lock manager object with a given name
119	 *
120	 * @param string $name
121	 * @return array
122	 * @throws Exception
123	 */
124	public function config( $name ) {
125		if ( !isset( $this->managers[$name] ) ) {
126			throw new Exception( "No lock manager defined with the name `$name`." );
127		}
128		$class = $this->managers[$name]['class'];
129
130		return [ 'class' => $class ] + $this->managers[$name]['config'];
131	}
132
133	/**
134	 * Get the default lock manager configured for the site.
135	 * Returns NullLockManager if no lock manager could be found.
136	 *
137	 * @codeCoverageIgnore
138	 * @deprecated since 1.35, seemingly unused, just call get() and catch any exception instead
139	 * @return LockManager
140	 */
141	public function getDefault() {
142		wfDeprecated( __METHOD__, '1.35' );
143
144		return isset( $this->managers['default'] )
145			? $this->get( 'default' )
146			: new NullLockManager( [] );
147	}
148
149	/**
150	 * Get the default lock manager configured for the site
151	 * or at least some other effective configured lock manager.
152	 * Throws an exception if no lock manager could be found.
153	 *
154	 * @codeCoverageIgnore
155	 * @deprecated since 1.35, seemingly unused, just call get() and catch any exception instead
156	 * @return LockManager
157	 * @throws Exception
158	 */
159	public function getAny() {
160		wfDeprecated( __METHOD__, '1.35' );
161
162		return isset( $this->managers['default'] )
163			? $this->get( 'default' )
164			: $this->get( 'fsLockManager' );
165	}
166}
167