RedisManager.php 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282
  1. <?php
  2. namespace Illuminate\Redis;
  3. use Closure;
  4. use Illuminate\Contracts\Redis\Factory;
  5. use Illuminate\Redis\Connections\Connection;
  6. use Illuminate\Redis\Connectors\PhpRedisConnector;
  7. use Illuminate\Redis\Connectors\PredisConnector;
  8. use Illuminate\Support\Arr;
  9. use Illuminate\Support\ConfigurationUrlParser;
  10. use InvalidArgumentException;
  11. use function Illuminate\Support\enum_value;
  12. /**
  13. * @mixin \Illuminate\Redis\Connections\Connection
  14. */
  15. class RedisManager implements Factory
  16. {
  17. /**
  18. * The application instance.
  19. *
  20. * @var \Illuminate\Contracts\Foundation\Application
  21. */
  22. protected $app;
  23. /**
  24. * The name of the default driver.
  25. *
  26. * @var string
  27. */
  28. protected $driver;
  29. /**
  30. * The registered custom driver creators.
  31. *
  32. * @var array
  33. */
  34. protected $customCreators = [];
  35. /**
  36. * The Redis server configurations.
  37. *
  38. * @var array
  39. */
  40. protected $config;
  41. /**
  42. * The Redis connections.
  43. *
  44. * @var mixed
  45. */
  46. protected $connections;
  47. /**
  48. * Indicates whether event dispatcher is set on connections.
  49. *
  50. * @var bool
  51. */
  52. protected $events = false;
  53. /**
  54. * Create a new Redis manager instance.
  55. *
  56. * @param \Illuminate\Contracts\Foundation\Application $app
  57. * @param string $driver
  58. * @param array $config
  59. */
  60. public function __construct($app, $driver, array $config)
  61. {
  62. $this->app = $app;
  63. $this->driver = $driver;
  64. $this->config = $config;
  65. }
  66. /**
  67. * Get a Redis connection by name.
  68. *
  69. * @param \UnitEnum|string|null $name
  70. * @return \Illuminate\Redis\Connections\Connection
  71. */
  72. public function connection($name = null)
  73. {
  74. $name = enum_value($name) ?: 'default';
  75. if (isset($this->connections[$name])) {
  76. return $this->connections[$name];
  77. }
  78. return $this->connections[$name] = $this->configure(
  79. $this->resolve($name), $name
  80. );
  81. }
  82. /**
  83. * Resolve the given connection by name.
  84. *
  85. * @param string|null $name
  86. * @return \Illuminate\Redis\Connections\Connection
  87. *
  88. * @throws \InvalidArgumentException
  89. */
  90. public function resolve($name = null)
  91. {
  92. $name = $name ?: 'default';
  93. $options = $this->config['options'] ?? [];
  94. if (isset($this->config[$name])) {
  95. return $this->connector()->connect(
  96. $this->parseConnectionConfiguration($this->config[$name]),
  97. array_merge(Arr::except($options, 'parameters'), ['parameters' => Arr::get($options, 'parameters.'.$name, Arr::get($options, 'parameters', []))])
  98. );
  99. }
  100. if (isset($this->config['clusters'][$name])) {
  101. return $this->resolveCluster($name);
  102. }
  103. throw new InvalidArgumentException("Redis connection [{$name}] not configured.");
  104. }
  105. /**
  106. * Resolve the given cluster connection by name.
  107. *
  108. * @param string $name
  109. * @return \Illuminate\Redis\Connections\Connection
  110. */
  111. protected function resolveCluster($name)
  112. {
  113. return $this->connector()->connectToCluster(
  114. array_map(function ($config) {
  115. return $this->parseConnectionConfiguration($config);
  116. }, $this->config['clusters'][$name]),
  117. $this->config['clusters']['options'] ?? [],
  118. $this->config['options'] ?? []
  119. );
  120. }
  121. /**
  122. * Configure the given connection to prepare it for commands.
  123. *
  124. * @param \Illuminate\Redis\Connections\Connection $connection
  125. * @param string $name
  126. * @return \Illuminate\Redis\Connections\Connection
  127. */
  128. protected function configure(Connection $connection, $name)
  129. {
  130. $connection->setName($name);
  131. if ($this->events && $this->app->bound('events')) {
  132. $connection->setEventDispatcher($this->app->make('events'));
  133. }
  134. return $connection;
  135. }
  136. /**
  137. * Get the connector instance for the current driver.
  138. *
  139. * @return \Illuminate\Contracts\Redis\Connector|null
  140. */
  141. protected function connector()
  142. {
  143. $customCreator = $this->customCreators[$this->driver] ?? null;
  144. if ($customCreator) {
  145. return $customCreator();
  146. }
  147. return match ($this->driver) {
  148. 'predis' => new PredisConnector,
  149. 'phpredis' => new PhpRedisConnector,
  150. default => null,
  151. };
  152. }
  153. /**
  154. * Parse the Redis connection configuration.
  155. *
  156. * @param mixed $config
  157. * @return array
  158. */
  159. protected function parseConnectionConfiguration($config)
  160. {
  161. $parsed = (new ConfigurationUrlParser)->parseConfiguration($config);
  162. $driver = strtolower($parsed['driver'] ?? '');
  163. if (in_array($driver, ['tcp', 'tls'])) {
  164. $parsed['scheme'] = $driver;
  165. }
  166. return array_filter($parsed, function ($key) {
  167. return $key !== 'driver';
  168. }, ARRAY_FILTER_USE_KEY);
  169. }
  170. /**
  171. * Return all of the created connections.
  172. *
  173. * @return array
  174. */
  175. public function connections()
  176. {
  177. return $this->connections;
  178. }
  179. /**
  180. * Enable the firing of Redis command events.
  181. *
  182. * @return void
  183. */
  184. public function enableEvents()
  185. {
  186. $this->events = true;
  187. }
  188. /**
  189. * Disable the firing of Redis command events.
  190. *
  191. * @return void
  192. */
  193. public function disableEvents()
  194. {
  195. $this->events = false;
  196. }
  197. /**
  198. * Set the default driver.
  199. *
  200. * @param string $driver
  201. * @return void
  202. */
  203. public function setDriver($driver)
  204. {
  205. $this->driver = $driver;
  206. }
  207. /**
  208. * Disconnect the given connection and remove from local cache.
  209. *
  210. * @param string|null $name
  211. * @return void
  212. */
  213. public function purge($name = null)
  214. {
  215. $name = $name ?: 'default';
  216. unset($this->connections[$name]);
  217. }
  218. /**
  219. * Register a custom driver creator Closure.
  220. *
  221. * @param string $driver
  222. * @param \Closure $callback
  223. *
  224. * @param-closure-this $this $callback
  225. *
  226. * @return $this
  227. */
  228. public function extend($driver, Closure $callback)
  229. {
  230. $this->customCreators[$driver] = $callback->bindTo($this, $this);
  231. return $this;
  232. }
  233. /**
  234. * Pass methods onto the default Redis connection.
  235. *
  236. * @param string $method
  237. * @param array $parameters
  238. * @return mixed
  239. */
  240. public function __call($method, $parameters)
  241. {
  242. return $this->connection()->{$method}(...$parameters);
  243. }
  244. }