Completed
Push — master ( 615331...30187f )
by Pedro García
02:31
created

FeaturedFlagsImpl::getEnabledValues()   B

Complexity

Conditions 4
Paths 4

Size

Total Lines 22
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 22
rs 8.9197
cc 4
eloc 13
nc 4
nop 2
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|null $filterParams
47
     * @return boolean
48
     */
49
    public function isEnabled($flagName, $filterParams = null)
50
    {
51
        $cacheKey = self::ISENABLED_PREFIX.$this->_getKey($flagName, $filterParams);
52
        $cacheValue = $this->_getCacheKey($cacheKey);
53
        if ($cacheValue)
54
        {
55
            return $cacheValue;
56
        }
57
58
        $flagsData = $this->_getDBFlagsData($flagName);
59
        foreach($flagsData as $flag){
60
            if ($this->_checkParams($flag['params'], $filterParams))
61
            {
62
                $this->_setCacheKey($cacheKey, true, $this->_getTimeout($flag['end_date']));
0 ignored issues
show
Documentation introduced by
true is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
Unused Code introduced by
The call to FeaturedFlagsImpl::_setCacheKey() has too many arguments starting with $this->_getTimeout($flag['end_date']).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
63
                return true;
64
            }
65
        }
66
67
        $this->_setCacheKey($cacheKey, false);
0 ignored issues
show
Documentation introduced by
false is of type boolean, but the function expects a string.

It seems like the type of the argument is not accepted by the function/method which you are calling.

In some cases, in particular if PHP’s automatic type-juggling kicks in this might be fine. In other cases, however this might be a bug.

We suggest to add an explicit type cast like in the following example:

function acceptsInteger($int) { }

$x = '123'; // string "123"

// Instead of
acceptsInteger($x);

// we recommend to use
acceptsInteger((integer) $x);
Loading history...
68
        return false;
69
    }
70
71
    /**
72
     * @param $flagName
73
     * @param $filterParams
74
     * @return null|array
75
     */
76
    public function getEnabledValues($flagName, $filterParams = null)
77
    {
78
        $cacheKey = self::GETVALUES_PREFIX.$this->_getKey($flagName, $filterParams);
79
        $cacheValue = $this->_getCacheKey($cacheKey);
80
        if ($cacheValue)
81
        {
82
            return $cacheValue;
83
        }
84
85
        $flagsData = $this->_getDBFlagsData($flagName);
86
        foreach($flagsData as $flag){
87
            if ($this->_checkParams($flag['params'], $filterParams))
88
            {
89
                $returnParams = json_decode($flag['return_params'], true);
90
                $this->_setCacheKey($cacheKey, $returnParams, $this->_getTimeout($flag['end_date']));
0 ignored issues
show
Unused Code introduced by
The call to FeaturedFlagsImpl::_setCacheKey() has too many arguments starting with $this->_getTimeout($flag['end_date']).

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
91
                return $returnParams;
92
            }
93
        }
94
95
        $this->_setCacheKey($cacheKey, null);
96
        return null;
97
    }
98
99
    /**
100
     * @param Redis $redis
101
     */
102
    public function setRedis(Redis $redis)
103
    {
104
        $this->_redis = $redis;
105
    }
106
107
    /**
108
     * @param string $cacheKey
109
     * @return null|array
110
     */
111
    private function _getCacheKey($cacheKey)
112
    {
113
        if (!is_null($this->_redis) && $this->_redis->get($cacheKey))
114
        {
115
                return $this->_redis->get($cacheKey);
116
        }
117
118
        return null;
119
    }
120
121
    /**
122
     * @param string $cacheKey
123
     * @param string $value
124
     */
125
    private function _setCacheKey($cacheKey, $value)
126
    {
127
        if (!is_null($this->_redis)) {
128
            $this->_redis->set($cacheKey, $value);
129
        }
130
    }
131
132
    /**
133
     * @return string
134
     */
135
    private function _getDate() {
136
        if ($this->_date) {
137
            return $this->_date;
138
        }
139
140
        return date("Y-m-d H:i:s");
141
    }
142
143
    /**
144
     * @param string $query
145
     * @param array $params
146
     * @return \mysqli_stmt
147
     */
148
    private function _getStmt($query, $params)
149
    {
150
        $stmt = $this->_pdo->prepare($query);
151
        foreach ($params as $field => $value) {
152
            $stmt->bindValue(":$field", $value);
153
        }
154
        return $stmt;
155
    }
156
157
    /**
158
     * @param string $flagName
159
     * @return array
160
     */
161
    private function _getDBFlagsData($flagName)
162
    {
163
        $query = "SELECT * FROM ".self::TABLE_NAME." WHERE 
164
        name = :flag AND 
165
        status = 1 AND
166
        (   (start_date IS NULL AND end_date IS NULL)
167
                OR
168
            (start_date <= :now AND :now <= end_date)
169
                OR
170
            (:now <= end_date AND (start_date IS NULL OR start_date = ''))
171
                OR
172
            (start_date <= :now AND (end_date IS NULL OR end_date = ''))
173
        )";
174
175
        $params = array(
176
            'flag' => $flagName,
177
            'now'  =>  $this->_getDate()
178
        );
179
180
        return $this->_executeForSelect($query, $params);
181
    }
182
183
    /**
184
     * @param string $query
185
     * @param array $params
186
     * @return array
187
     */
188
    private function _executeForSelect($query, $params = array())
189
    {
190
        $stmt = $this->_getStmt($query, $params);
191
        $stmt->execute();
192
        return $stmt->fetchAll();
193
    }
194
195
    /**
196
     * @param array $flagParams
197
     * @param array $filterParams
198
     * @return boolean
199
     */
200
    private function _compareParams($flagParams, $filterParams)
201
    {
202
        $checkParams = true;
203
        foreach($filterParams as $key => $value)
204
        {
205
            $checkParams = $checkParams && isset($flagParams[$key]) && $flagParams[$key] == $value;
206
        }
207
208
        return $checkParams;
209
    }
210
211
    /**
212
     * @param string $flagParamsJson
213
     * @param array $filterParams
214
     * @return boolean
215
     */
216
    private function _checkParams($flagParamsJson, $filterParams = null)
217
    {
218
        if (!$filterParams) {
219
            return true;
220
        }
221
222
        $flagParamsData = json_decode($flagParamsJson, true);
223
        if (!is_array($flagParamsData) || count($flagParamsData) === 0) {
224
            return false;
225
        }
226
227
        return $this->_compareParams($flagParamsData, $filterParams);
228
    }
229
230
    /**
231
     * @param string $flagName
232
     * @param array|null $filterParams
233
     * @return boolean
234
     */
235
    private function _getKey($flagName, $filterParams = null)
236
    {
237
        return "FF_".$flagName.json_encode($filterParams);
238
    }
239
240
    /**
241
     * @param string $endDate
242
     * @return int
243
     */
244
    private function _getTimeout($endDate)
245
    {
246
        if (!$endDate) {
247
            return 0;
248
        }
249
250
        return strtotime($endDate) - strtotime($this->_getDate());
251
    }
252
}
253