1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace FeaturedFlags; |
4
|
|
|
|
5
|
|
|
use PDO; |
6
|
|
|
use Redis; |
7
|
|
|
|
8
|
|
|
class FeaturedFlagsImpl implements FeaturedFlags |
9
|
|
|
{ |
10
|
|
|
protected $_pdo; |
11
|
|
|
protected $_redis; |
12
|
|
|
protected $_date; |
13
|
|
|
|
14
|
|
|
CONST TABLE_NAME = 'featured_flags'; |
15
|
|
|
CONST ISENABLED_PREFIX = 'isEnabled_'; |
16
|
|
|
CONST GETVALUES_PREFIX = 'getEnabledValues_'; |
17
|
|
|
|
18
|
|
|
/** |
19
|
|
|
* FeaturedFlags constructor. |
20
|
|
|
* @param PDO $pdo |
21
|
|
|
* @param Redis|null $redis |
22
|
|
|
* @param string|null $date |
23
|
|
|
*/ |
24
|
|
|
public function __construct(PDO $pdo, Redis $redis = null, $date = null) |
25
|
|
|
{ |
26
|
|
|
$this->_pdo = $pdo; |
27
|
|
|
if ($redis) { |
28
|
|
|
$this->_redis = $redis; |
29
|
|
|
} |
30
|
|
|
if (!is_null($date)) { |
31
|
|
|
$this->_date = $date; |
32
|
|
|
} |
33
|
|
|
} |
34
|
|
|
|
35
|
|
|
/** |
36
|
|
|
* @param PDO $pdo |
37
|
|
|
* @param Redis $redis |
38
|
|
|
* @return FeaturedFlags |
39
|
|
|
*/ |
40
|
|
|
public static function getInstance(PDO $pdo, Redis $redis = null) { |
41
|
|
|
return new self($pdo, $redis); |
42
|
|
|
} |
43
|
|
|
|
44
|
|
|
/** |
45
|
|
|
* @param string $flagName |
46
|
|
|
* @param array $filterParams |
47
|
|
|
* @return boolean |
48
|
|
|
*/ |
49
|
|
|
public function isEnabled($flagName, $filterParams = null) |
50
|
|
|
{ |
51
|
|
|
$cacheKey = self::ISENABLED_PREFIX.$this->_getKey($flagName, $filterParams); |
52
|
|
|
$cacheModel = $this->_getCacheModel($cacheKey); |
53
|
|
|
if ($cacheModel instanceof FeaturedFlagsModel) |
54
|
|
|
{ |
55
|
|
|
return $cacheModel->isEnabled(); |
56
|
|
|
} |
57
|
|
|
|
58
|
|
|
$featureFlagModel = $this->_getBDFlag($flagName, $filterParams); |
|
|
|
|
59
|
|
|
$this->_setCacheKey($cacheKey, $featureFlagModel); |
60
|
|
|
return $featureFlagModel->isEnabled(); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* @param $flagName |
65
|
|
|
* @param $filterParams |
66
|
|
|
* @return array |
67
|
|
|
*/ |
68
|
|
|
public function getEnabledValues($flagName, $filterParams = null) |
69
|
|
|
{ |
70
|
|
|
$cacheKey = self::GETVALUES_PREFIX.$this->_getKey($flagName, $filterParams); |
71
|
|
|
$cacheValue = $this->_getCacheModel($cacheKey); |
72
|
|
|
if ($cacheValue instanceof FeaturedFlagsModel) |
73
|
|
|
{ |
74
|
|
|
return $cacheValue->getParamsArray(); |
75
|
|
|
} |
76
|
|
|
|
77
|
|
|
$featureFlagModel = $this->_getBDFlag($flagName, $filterParams); |
78
|
|
|
$this->_setCacheKey($cacheKey, $featureFlagModel); |
79
|
|
|
return $featureFlagModel->getParamsArray(); |
80
|
|
|
} |
81
|
|
|
|
82
|
|
|
/** |
83
|
|
|
* @param Redis $redis |
84
|
|
|
*/ |
85
|
|
|
public function setRedis(Redis $redis) |
86
|
|
|
{ |
87
|
|
|
$this->_redis = $redis; |
88
|
|
|
} |
89
|
|
|
|
90
|
|
|
/** |
91
|
|
|
* @param string $flagName |
92
|
|
|
* @param array $filterParams |
93
|
|
|
* @return FeaturedFlagsModel |
94
|
|
|
*/ |
95
|
|
|
private function _getBDFlag($flagName, $filterParams) |
96
|
|
|
{ |
97
|
|
|
$flagsData = $this->_getDBFlagsData($flagName); |
98
|
|
|
foreach($flagsData as $flag){ |
99
|
|
|
if ($this->_checkParams($flag['params'], $filterParams)) |
100
|
|
|
{ |
101
|
|
|
return new FeaturedFlagsModel(true, $flag['return_params'], $flag['end_date']); |
102
|
|
|
} |
103
|
|
|
} |
104
|
|
|
|
105
|
|
|
return new FeaturedFlagsModel(false); |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* @param string $cacheKey |
110
|
|
|
* @return FeaturedFlagsModel |
111
|
|
|
*/ |
112
|
|
|
private function _getCacheModel($cacheKey) |
113
|
|
|
{ |
114
|
|
|
if (!is_null($this->_redis) && $this->_redis->get($cacheKey)) |
115
|
|
|
{ |
116
|
|
|
return $this->_redis->get($cacheKey); |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
return null; |
120
|
|
|
} |
121
|
|
|
|
122
|
|
|
/** |
123
|
|
|
* @param string $cacheKey |
124
|
|
|
* @param FeaturedFlagsModel $featuredFlagsModel |
125
|
|
|
*/ |
126
|
|
|
private function _setCacheKey($cacheKey, FeaturedFlagsModel $featuredFlagsModel) |
127
|
|
|
{ |
128
|
|
|
if (!is_null($this->_redis)) { |
129
|
|
|
$timeOut = $this->_getTimeout($featuredFlagsModel->getEndDate()); |
130
|
|
|
$this->_redis->set($cacheKey, $featuredFlagsModel, $timeOut); |
131
|
|
|
} |
132
|
|
|
} |
133
|
|
|
|
134
|
|
|
/** |
135
|
|
|
* @param string $flagName |
136
|
|
|
* @return array |
137
|
|
|
*/ |
138
|
|
|
private function _getDBFlagsData($flagName) |
139
|
|
|
{ |
140
|
|
|
$query = "SELECT * FROM ".self::TABLE_NAME." WHERE |
141
|
|
|
name = :flag AND |
142
|
|
|
status = 1 AND |
143
|
|
|
( (start_date IS NULL AND end_date IS NULL) |
144
|
|
|
OR |
145
|
|
|
(start_date <= :now AND :now <= end_date) |
146
|
|
|
OR |
147
|
|
|
(:now <= end_date AND (start_date IS NULL OR start_date = '')) |
148
|
|
|
OR |
149
|
|
|
(start_date <= :now AND (end_date IS NULL OR end_date = '')) |
150
|
|
|
)"; |
151
|
|
|
|
152
|
|
|
$params = array( |
153
|
|
|
'flag' => $flagName, |
154
|
|
|
'now' => $this->_getDate() |
155
|
|
|
); |
156
|
|
|
|
157
|
|
|
$stmt = $this->_pdo->prepare($query); |
158
|
|
|
foreach ($params as $field => $value) { |
159
|
|
|
$stmt->bindValue(":$field", $value); |
160
|
|
|
} |
161
|
|
|
$stmt->execute(); |
162
|
|
|
return $stmt->fetchAll(); |
163
|
|
|
} |
164
|
|
|
|
165
|
|
|
/** |
166
|
|
|
* @return string |
167
|
|
|
*/ |
168
|
|
|
private function _getDate() { |
169
|
|
|
if ($this->_date) { |
170
|
|
|
return $this->_date; |
171
|
|
|
} |
172
|
|
|
|
173
|
|
|
return date("Y-m-d H:i:s"); |
174
|
|
|
} |
175
|
|
|
|
176
|
|
|
/** |
177
|
|
|
* @param array $flagParams |
178
|
|
|
* @param array $filterParams |
179
|
|
|
* @return boolean |
180
|
|
|
*/ |
181
|
|
|
private function _compareParams($flagParams, $filterParams) |
182
|
|
|
{ |
183
|
|
|
$checkParams = true; |
184
|
|
|
foreach($filterParams as $key => $value) |
185
|
|
|
{ |
186
|
|
|
$checkParams = $checkParams && isset($flagParams[$key]) && $flagParams[$key] == $value; |
187
|
|
|
} |
188
|
|
|
|
189
|
|
|
return $checkParams; |
190
|
|
|
} |
191
|
|
|
|
192
|
|
|
/** |
193
|
|
|
* @param string $flagParamsJson |
194
|
|
|
* @param array $filterParams |
195
|
|
|
* @return boolean |
196
|
|
|
*/ |
197
|
|
|
private function _checkParams($flagParamsJson, $filterParams = null) |
198
|
|
|
{ |
199
|
|
|
if (!$filterParams) { |
200
|
|
|
return true; |
201
|
|
|
} |
202
|
|
|
|
203
|
|
|
$flagParamsData = json_decode($flagParamsJson, true); |
204
|
|
|
if (!is_array($flagParamsData) || count($flagParamsData) === 0) { |
205
|
|
|
return false; |
206
|
|
|
} |
207
|
|
|
|
208
|
|
|
return $this->_compareParams($flagParamsData, $filterParams); |
209
|
|
|
} |
210
|
|
|
|
211
|
|
|
/** |
212
|
|
|
* @param string $flagName |
213
|
|
|
* @param array|null $filterParams |
214
|
|
|
* @return boolean |
215
|
|
|
*/ |
216
|
|
|
private function _getKey($flagName, $filterParams = null) |
217
|
|
|
{ |
218
|
|
|
return "FF_".$flagName.json_encode($filterParams); |
219
|
|
|
} |
220
|
|
|
|
221
|
|
|
/** |
222
|
|
|
* @param string $endDate |
223
|
|
|
* @return int |
224
|
|
|
*/ |
225
|
|
|
private function _getTimeout($endDate) |
226
|
|
|
{ |
227
|
|
|
if (!$endDate) { |
228
|
|
|
return 0; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
return strtotime($endDate) - strtotime($this->_getDate()); |
232
|
|
|
} |
233
|
|
|
} |
234
|
|
|
|
This check looks at variables that have been passed in as parameters and are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.