Completed
Push — 1.x ( 1267b2...d54394 )
by Cy
01:58
created

RedisSentinelDatabase   A

Complexity

Total Complexity 7

Size/Duplication

Total Lines 123
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 4

Importance

Changes 0
Metric Value
wmc 7
lcom 1
cbo 4
dl 0
loc 123
rs 10
c 0
b 0
f 0

4 Methods

Rating   Name   Duplication   Size   Complexity  
A subscribe() 0 9 1
A createSingleClients() 0 20 3
A createSingleClient() 0 22 1
A setSentinelConnectionOptions() 0 10 2
1
<?php
2
3
namespace Monospice\LaravelRedisSentinel;
4
5
use Closure;
6
use Illuminate\Redis\Database as RedisDatabase;
7
use Illuminate\Support\Arr;
8
use Monospice\LaravelRedisSentinel\PredisConnection;
9
use Monospice\SpicyIdentifiers\DynamicMethod;
10
11
/**
12
 * Enables Laravel's Redis database driver to accept configuration options for
13
 * Redis Sentinel connections independently.
14
 *
15
 * By default, Laravel's Redis service permits a single set of configuration
16
 * options for all of the Redis connections passed to the Predis client. This
17
 * prevents us from declaring separate parameters for individual Redis services
18
 * managed by Sentinel. For example, we may wish to connect to a separate Redis
19
 * Sentinel replication group, or use separate Redis databases for caching,
20
 * queues, and sessions. This wrapper class enables us to declare parameters
21
 * for each connection in the "redis-sentinel" block of the database
22
 * configuration which it will use to configure individual clients.
23
 *
24
 * @category Package
25
 * @package  Monospice\LaravelRedisSentinel
26
 * @author   Cy Rossignol <[email protected]>
27
 * @license  See LICENSE file
28
 * @link     https://github.com/monospice/laravel-redis-sentinel-drivers
29
 */
30
class RedisSentinelDatabase extends RedisDatabase
31
{
32
    /**
33
     * Configuration options specific to Sentinel connection operation
34
     *
35
     * We cannot pass these options as an array to the Predis client.
36
     * Instead, we'll set them on the connection directly using methods
37
     * provided by the SentinelReplication class of the Predis package.
38
     *
39
     * @var array
40
     */
41
    protected $sentinelConnectionOptionKeys = [
42
        'sentinel_timeout',
43
        'retry_wait',
44
        'retry_limit',
45
        'update_sentinels',
46
    ];
47
48
    /**
49
     * Subscribe to a set of given channels for messages.
50
     *
51
     * @param array|string $channels   The names of the channels to subscribe to
52
     * @param Closure      $callback   Executed for each message. Receives the
53
     * message string in the first argument and the message channel as the
54
     * second argument. Return FALSE to unsubscribe.
55
     * @param string|null  $connection The connection to subscribe on.
56
     * @param string       $method     The subscription command ("subscribe" or
57
     * "psubscribe").
58
     *
59
     * @return void
60
     */
61
    public function subscribe(
62
        $channels,
63
        Closure $callback,
64
        $connection = null,
65
        $method = 'subscribe'
66
    ) {
67
        $this->connection($connection)
68
            ->createSubscription($channels, $callback, $method);
69
    }
70
71
    /**
72
     * Create an array of single connection clients.
73
     *
74
     * @param array $servers The set of options for each Sentinel connection
75
     * @param array $options The global options shared by all Sentinel clients
76
     *
77
     * @return array Each element contains a Predis client that represents a
78
     * connection defined in the 'redis-sentinel' block in config/database.php
79
     */
80
    protected function createSingleClients(array $servers, array $options = [])
81
    {
82
        $clients = [];
83
84
        // Laravel < 5.1 doesn't extract the global options from the connection
85
        // configuration for us
86
        if (array_key_exists('options', $servers)) {
87
            $options = (array) Arr::pull($servers, 'options');
88
        }
89
90
        // Automatically set "replication" to "sentinel". This is the Sentinel
91
        // driver, after all.
92
        $options['replication'] = 'sentinel';
93
94
        foreach ($servers as $key => $server) {
95
            $clients[$key] = $this->createSingleClient($server, $options);
96
        }
97
98
        return $clients;
99
    }
100
101
    /**
102
     * Create a Predis client instance for a Redis Sentinel connection
103
     *
104
     * @param array $server  The configuration options for the connection
105
     * @param array $options The global options shared by all Sentinel clients
106
     *
107
     * @return Client The Predis Client instance
0 ignored issues
show
Documentation introduced by
Should the return type not be PredisConnection?

This check compares the return type specified in the @return annotation of a function or method doc comment with the types returned by the function and raises an issue if they mismatch.

Loading history...
108
     */
109
    protected function createSingleClient(array $server, array $options)
110
    {
111
        // Merge the global options shared by all Sentinel connections with
112
        // connection-specific options
113
        $clientOpts = (array) Arr::pull($server, 'options');
114
        $clientOpts = array_merge($options, $clientOpts);
115
116
        $sentinelKeys = array_flip($this->sentinelConnectionOptionKeys);
117
118
        // Extract the array of Sentinel connection options from the rest of
119
        // the client options
120
        $sentinelOpts = array_intersect_key($clientOpts, $sentinelKeys);
121
122
        // Filter the Sentinel connection options elements from the client
123
        // options array
124
        $clientOpts = array_diff_key($clientOpts, $sentinelKeys);
125
126
        $client = new PredisConnection($server, $clientOpts);
127
        $this->setSentinelConnectionOptions($client, $sentinelOpts);
128
129
        return $client;
130
    }
131
132
    /**
133
     * Sets the Sentinel-specific connection options on a Predis Client
134
     * connection
135
     *
136
     * @param Client $client       The Predis Client to set options for
0 ignored issues
show
Documentation introduced by
Should the type for parameter $client not be PredisConnection?

This check looks for @param annotations where the type inferred by our type inference engine differs from the declared type.

It makes a suggestion as to what type it considers more descriptive.

Most often this is a case of a parameter that can be null in addition to its declared types.

Loading history...
137
     * @param array  $sentinelOpts The options supported by Predis for
138
     * Sentinel-specific connections
139
     *
140
     * @return void
141
     */
142
    protected function setSentinelConnectionOptions(
143
        PredisConnection $client,
144
        array $sentinelOpts
145
    ) {
146
        foreach ($sentinelOpts as $option => $value) {
147
            DynamicMethod::parseFromUnderscore($option)
148
                ->prepend('set')
149
                ->callOn($client, [ $value ]);
150
        }
151
    }
152
}
153